Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85fdcff103 | |||
| 1e15e90d32 | |||
| aae6087f90 | |||
| 0955bb39e3 | |||
| ccc7f1bc8c | |||
| 6b1f3d7124 | |||
| 5439aeb081 | |||
| 2cc1e3d283 | |||
| 7708c479e8 | |||
| 70c5858c94 | |||
| c881259f55 | |||
| 6800d0d7a9 | |||
| 0e716e083c | |||
| aa3ac640cb | |||
| 558616311c | |||
| b4ebf4d363 | |||
| fc44f649c9 |
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
run: dotnet build --configuration Release --no-restore
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack --configuration Release --no-build --output nupkgs
|
||||
run: dotnet pack IronJava.Core/IronJava.Core.csproj --configuration Release --no-build --output nupkgs
|
||||
|
||||
- name: Upload NuGet package
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -124,9 +124,13 @@ jobs:
|
||||
|
||||
- name: Publish to NuGet
|
||||
run: |
|
||||
if [ -z "$NUGET_API_KEY" ]; then
|
||||
echo "Error: NUGET_API_KEY is not set"
|
||||
exit 1
|
||||
fi
|
||||
for package in nupkgs/*.nupkg; do
|
||||
echo "Publishing $package"
|
||||
dotnet nuget push "$package" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
dotnet nuget push "$package" --api-key "$NUGET_API_KEY" --source "https://api.nuget.org/v3/index.json" --skip-duplicate
|
||||
done
|
||||
env:
|
||||
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
|
||||
1019
API_SPECIFICATION.md
Normal file
1019
API_SPECIFICATION.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Query;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Query;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Benchmarks
|
||||
namespace MarketAlly.IronJava.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public class AstTraversalBenchmarks
|
||||
@@ -108,7 +108,7 @@ namespace IronJava.Benchmarks
|
||||
|
||||
public void Reset() => NodeCount = 0;
|
||||
|
||||
protected override void DefaultVisit(IronJava.Core.AST.JavaNode node)
|
||||
protected override void DefaultVisit(MarketAlly.IronJava.Core.AST.JavaNode node)
|
||||
{
|
||||
NodeCount++;
|
||||
base.DefaultVisit(node);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>MarketAlly.IronJava.Benchmarks</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using IronJava.Core;
|
||||
using MarketAlly.IronJava.Core;
|
||||
|
||||
namespace IronJava.Benchmarks
|
||||
namespace MarketAlly.IronJava.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(warmupCount: 3, iterationCount: 5)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
namespace IronJava.Benchmarks
|
||||
namespace MarketAlly.IronJava.Benchmarks
|
||||
{
|
||||
class Program
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Transformation;
|
||||
using IronJava.Core.Serialization;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Transformation;
|
||||
using MarketAlly.IronJava.Core.Serialization;
|
||||
|
||||
namespace IronJava.Benchmarks
|
||||
namespace MarketAlly.IronJava.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public class TransformationBenchmarks
|
||||
|
||||
@@ -4,10 +4,10 @@ using System.Linq;
|
||||
using Antlr4.Runtime;
|
||||
using Antlr4.Runtime.Misc;
|
||||
using Antlr4.Runtime.Tree;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.Grammar;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.Grammar;
|
||||
|
||||
namespace IronJava.Core.AST.Builders
|
||||
namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds a typed AST from ANTLR parse tree.
|
||||
@@ -196,12 +196,12 @@ namespace IronJava.Core.AST.Builders
|
||||
var typeParameters = BuildTypeParameters(context.typeParameters());
|
||||
var superClass = context.superclass() != null ? BuildTypeReference(context.superclass().classType()) : null;
|
||||
var interfaces = BuildInterfaces(context.superinterfaces());
|
||||
var members = BuildClassMembers(context.classBody());
|
||||
var bodyResult = BuildClassBody(context.classBody());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
return new ClassDeclaration(
|
||||
location, name, modifiers, annotations, typeParameters,
|
||||
superClass, interfaces, members, javaDoc
|
||||
superClass, interfaces, bodyResult.Members, bodyResult.NestedTypes, javaDoc, false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -213,12 +213,12 @@ namespace IronJava.Core.AST.Builders
|
||||
var name = context.identifier().GetText();
|
||||
var typeParameters = BuildTypeParameters(context.typeParameters());
|
||||
var extendedInterfaces = BuildExtendedInterfaces(context.extendsInterfaces());
|
||||
var members = BuildInterfaceMembers(context.interfaceBody());
|
||||
var bodyResult = BuildInterfaceBody(context.interfaceBody());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
return new InterfaceDeclaration(
|
||||
location, name, modifiers, annotations, typeParameters,
|
||||
extendedInterfaces, members, javaDoc
|
||||
extendedInterfaces, bodyResult.Members, bodyResult.NestedTypes, javaDoc
|
||||
);
|
||||
}
|
||||
|
||||
@@ -231,12 +231,15 @@ namespace IronJava.Core.AST.Builders
|
||||
var interfaces = BuildInterfaces(context.superinterfaces());
|
||||
var enumBody = context.enumBody();
|
||||
var constants = BuildEnumConstants(enumBody.enumConstantList());
|
||||
var members = BuildEnumMembers(enumBody.enumBodyDeclarations());
|
||||
var bodyResult = BuildEnumBody(enumBody.enumBodyDeclarations());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
return new EnumDeclaration(
|
||||
location, name, modifiers, annotations,
|
||||
interfaces, constants, members, javaDoc
|
||||
interfaces, constants,
|
||||
bodyResult?.Members ?? new List<MemberDeclaration>(),
|
||||
bodyResult?.NestedTypes ?? new List<TypeDeclaration>(),
|
||||
javaDoc
|
||||
);
|
||||
}
|
||||
|
||||
@@ -249,8 +252,9 @@ namespace IronJava.Core.AST.Builders
|
||||
var members = BuildAnnotationMembers(context.annotationTypeBody());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
// Annotations don't support nested types in Java
|
||||
return new AnnotationDeclaration(
|
||||
location, name, modifiers, annotations, members, javaDoc
|
||||
location, name, modifiers, annotations, members, new List<TypeDeclaration>(), javaDoc
|
||||
);
|
||||
}
|
||||
|
||||
@@ -293,11 +297,24 @@ namespace IronJava.Core.AST.Builders
|
||||
var annotations = new List<Annotation>();
|
||||
foreach (var context in contexts)
|
||||
{
|
||||
// Check if this is directly an annotation context
|
||||
if (context is Java9Parser.AnnotationContext annotationContext)
|
||||
{
|
||||
var annotation = BuildAnnotation(annotationContext);
|
||||
if (annotation != null) annotations.Add(annotation);
|
||||
}
|
||||
// Check if this is a modifier that contains an annotation
|
||||
else if (context is ParserRuleContext ruleContext && ruleContext.ChildCount > 0)
|
||||
{
|
||||
// The first child of a modifier rule that represents an annotation
|
||||
// will be an AnnotationContext
|
||||
var firstChild = ruleContext.GetChild(0);
|
||||
if (firstChild is Java9Parser.AnnotationContext childAnnotation)
|
||||
{
|
||||
var annotation = BuildAnnotation(childAnnotation);
|
||||
if (annotation != null) annotations.Add(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
@@ -308,25 +325,37 @@ namespace IronJava.Core.AST.Builders
|
||||
TypeReference? type = null;
|
||||
var arguments = new List<AnnotationArgument>();
|
||||
|
||||
|
||||
// Annotations can be NormalAnnotation, MarkerAnnotation, or SingleElementAnnotation
|
||||
if (context.normalAnnotation() != null)
|
||||
{
|
||||
var normalAnn = context.normalAnnotation();
|
||||
type = BuildTypeReference(normalAnn.typeName());
|
||||
if (type == null) return null;
|
||||
// Don't return early - try to build the type from the name
|
||||
if (type == null)
|
||||
{
|
||||
var typeName = normalAnn.typeName().GetText();
|
||||
type = new ClassOrInterfaceType(GetSourceRange(normalAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
||||
}
|
||||
|
||||
if (normalAnn.elementValuePairList() != null)
|
||||
{
|
||||
foreach (var pair in normalAnn.elementValuePairList().elementValuePair())
|
||||
{
|
||||
var name = pair.identifier().GetText();
|
||||
var value = BuildExpression(pair.elementValue());
|
||||
if (value != null)
|
||||
var value = BuildElementValue(pair.elementValue());
|
||||
|
||||
// Debug - always add the argument even if value is null
|
||||
// If value is null, create a string literal as fallback
|
||||
if (value == null)
|
||||
{
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
GetSourceRange(pair), name, value
|
||||
));
|
||||
var elementText = pair.elementValue().GetText();
|
||||
value = new LiteralExpression(GetSourceRange(pair.elementValue()), elementText, LiteralKind.String);
|
||||
}
|
||||
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
GetSourceRange(pair), name, value
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,30 +363,89 @@ namespace IronJava.Core.AST.Builders
|
||||
{
|
||||
var markerAnn = context.markerAnnotation();
|
||||
type = BuildTypeReference(markerAnn.typeName());
|
||||
if (type == null) return null;
|
||||
if (type == null)
|
||||
{
|
||||
var typeName = markerAnn.typeName().GetText();
|
||||
type = new ClassOrInterfaceType(GetSourceRange(markerAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
||||
}
|
||||
// Marker annotations have no arguments
|
||||
}
|
||||
else if (context.singleElementAnnotation() != null)
|
||||
{
|
||||
var singleAnn = context.singleElementAnnotation();
|
||||
type = BuildTypeReference(singleAnn.typeName());
|
||||
if (type == null) return null;
|
||||
if (type == null)
|
||||
{
|
||||
var typeName = singleAnn.typeName().GetText();
|
||||
type = new ClassOrInterfaceType(GetSourceRange(singleAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
||||
}
|
||||
|
||||
if (singleAnn.elementValue() != null)
|
||||
{
|
||||
var value = BuildExpression(singleAnn.elementValue());
|
||||
if (value != null)
|
||||
var value = BuildElementValue(singleAnn.elementValue());
|
||||
|
||||
// Fallback if BuildElementValue returns null
|
||||
if (value == null)
|
||||
{
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
location, "value", value
|
||||
));
|
||||
var elementText = singleAnn.elementValue().GetText();
|
||||
value = new LiteralExpression(GetSourceRange(singleAnn.elementValue()), elementText, LiteralKind.String);
|
||||
}
|
||||
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
location, "value", value
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return type != null ? new Annotation(location, type, arguments) : null;
|
||||
}
|
||||
|
||||
private Expression? BuildElementValue(Java9Parser.ElementValueContext context)
|
||||
{
|
||||
if (context.conditionalExpression() != null)
|
||||
{
|
||||
var expr = BuildExpression(context.conditionalExpression());
|
||||
// If BuildExpression returns null, try to parse it as a string literal
|
||||
if (expr == null)
|
||||
{
|
||||
var text = context.conditionalExpression().GetText();
|
||||
if (text.StartsWith('"') && text.EndsWith('"'))
|
||||
{
|
||||
// Remove quotes and create a string literal
|
||||
var value = text.Substring(1, text.Length - 2);
|
||||
expr = new LiteralExpression(GetSourceRange(context), value, LiteralKind.String);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
else if (context.annotation() != null)
|
||||
{
|
||||
var annotation = BuildAnnotation(context.annotation());
|
||||
if (annotation != null)
|
||||
{
|
||||
return new AnnotationExpression(GetSourceRange(context), annotation);
|
||||
}
|
||||
}
|
||||
else if (context.elementValueArrayInitializer() != null)
|
||||
{
|
||||
var arrayInit = context.elementValueArrayInitializer();
|
||||
var elements = new List<Expression>();
|
||||
|
||||
if (arrayInit.elementValueList() != null)
|
||||
{
|
||||
foreach (var elementValue in arrayInit.elementValueList().elementValue())
|
||||
{
|
||||
var element = BuildElementValue(elementValue);
|
||||
if (element != null) elements.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayInitializer(GetSourceRange(arrayInit), elements);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<TypeParameter> BuildTypeParameters(Java9Parser.TypeParametersContext? context)
|
||||
{
|
||||
if (context == null) return new List<TypeParameter>();
|
||||
@@ -410,8 +498,8 @@ namespace IronJava.Core.AST.Builders
|
||||
Java9Parser.ArrayTypeContext array => BuildArrayType(array),
|
||||
Java9Parser.TypeVariableContext typeVar => BuildTypeVariable(typeVar),
|
||||
Java9Parser.ClassTypeContext classType => BuildClassType(classType),
|
||||
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
||||
Java9Parser.TypeNameContext typeName => BuildTypeName(typeName),
|
||||
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -667,6 +755,54 @@ namespace IronJava.Core.AST.Builders
|
||||
return members;
|
||||
}
|
||||
|
||||
private ClassBodyResult BuildClassBody(Java9Parser.ClassBodyContext context)
|
||||
{
|
||||
var result = new ClassBodyResult();
|
||||
|
||||
foreach (var declaration in context.classBodyDeclaration())
|
||||
{
|
||||
if (declaration.classMemberDeclaration() != null)
|
||||
{
|
||||
var classMemberContext = declaration.classMemberDeclaration();
|
||||
|
||||
// Check if it's a nested type declaration
|
||||
if (classMemberContext.classDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.classDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else if (classMemberContext.interfaceDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.interfaceDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a regular member (field or method)
|
||||
var member = BuildClassMember(classMemberContext);
|
||||
if (member != null) result.Members.Add(member);
|
||||
}
|
||||
}
|
||||
else if (declaration.instanceInitializer() != null)
|
||||
{
|
||||
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.staticInitializer() != null)
|
||||
{
|
||||
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.constructorDeclaration() != null)
|
||||
{
|
||||
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
||||
if (constructor != null) result.Members.Add(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private MemberDeclaration? BuildClassMember(Java9Parser.ClassMemberDeclarationContext context)
|
||||
{
|
||||
if (context.fieldDeclaration() != null)
|
||||
@@ -677,15 +813,8 @@ namespace IronJava.Core.AST.Builders
|
||||
{
|
||||
return BuildMethodDeclaration(context.methodDeclaration());
|
||||
}
|
||||
else if (context.classDeclaration() != null)
|
||||
{
|
||||
return Visit(context.classDeclaration()) as MemberDeclaration;
|
||||
}
|
||||
else if (context.interfaceDeclaration() != null)
|
||||
{
|
||||
return Visit(context.interfaceDeclaration()) as MemberDeclaration;
|
||||
}
|
||||
|
||||
// Nested types are now handled in BuildClassBody
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -935,6 +1064,13 @@ namespace IronJava.Core.AST.Builders
|
||||
|
||||
private Parameter? BuildLastParameter(Java9Parser.LastFormalParameterContext context)
|
||||
{
|
||||
// Check if this is just a regular parameter (not varargs)
|
||||
if (context.formalParameter() != null)
|
||||
{
|
||||
return BuildParameter(context.formalParameter());
|
||||
}
|
||||
|
||||
// Otherwise, it's a varargs parameter
|
||||
var location = GetSourceRange(context);
|
||||
var modifiers = BuildModifiers(context.variableModifier());
|
||||
var annotations = BuildAnnotations(context.variableModifier());
|
||||
@@ -944,7 +1080,7 @@ namespace IronJava.Core.AST.Builders
|
||||
var declaratorId = context.variableDeclaratorId();
|
||||
var name = declaratorId.identifier().GetText();
|
||||
var isFinal = modifiers.HasFlag(Modifiers.Final);
|
||||
var isVarArgs = context.GetChild(context.ChildCount - 2)?.GetText() == "...";
|
||||
var isVarArgs = true; // This branch is only for varargs
|
||||
|
||||
return new Parameter(location, type, name, isVarArgs, isFinal, annotations);
|
||||
}
|
||||
@@ -1040,6 +1176,37 @@ namespace IronJava.Core.AST.Builders
|
||||
return members;
|
||||
}
|
||||
|
||||
private ClassBodyResult BuildInterfaceBody(Java9Parser.InterfaceBodyContext context)
|
||||
{
|
||||
var result = new ClassBodyResult();
|
||||
|
||||
foreach (var declaration in context.interfaceMemberDeclaration())
|
||||
{
|
||||
if (declaration.constantDeclaration() != null)
|
||||
{
|
||||
var constant = BuildConstantDeclaration(declaration.constantDeclaration());
|
||||
if (constant != null) result.Members.Add(constant);
|
||||
}
|
||||
else if (declaration.interfaceMethodDeclaration() != null)
|
||||
{
|
||||
var method = BuildInterfaceMethodDeclaration(declaration.interfaceMethodDeclaration());
|
||||
if (method != null) result.Members.Add(method);
|
||||
}
|
||||
else if (declaration.classDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(declaration.classDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else if (declaration.interfaceDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(declaration.interfaceDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private FieldDeclaration? BuildConstantDeclaration(Java9Parser.ConstantDeclarationContext context)
|
||||
{
|
||||
var location = GetSourceRange(context);
|
||||
@@ -1125,7 +1292,9 @@ namespace IronJava.Core.AST.Builders
|
||||
null,
|
||||
new List<TypeReference>(),
|
||||
members,
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1170,6 +1339,56 @@ namespace IronJava.Core.AST.Builders
|
||||
return members;
|
||||
}
|
||||
|
||||
private ClassBodyResult? BuildEnumBody(Java9Parser.EnumBodyDeclarationsContext? context)
|
||||
{
|
||||
if (context == null) return null;
|
||||
|
||||
var result = new ClassBodyResult();
|
||||
|
||||
foreach (var declaration in context.classBodyDeclaration())
|
||||
{
|
||||
if (declaration.classMemberDeclaration() != null)
|
||||
{
|
||||
var classMemberContext = declaration.classMemberDeclaration();
|
||||
|
||||
// Check if it's a nested type declaration
|
||||
if (classMemberContext.classDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.classDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else if (classMemberContext.interfaceDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.interfaceDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a regular member (field or method)
|
||||
var member = BuildClassMember(classMemberContext);
|
||||
if (member != null) result.Members.Add(member);
|
||||
}
|
||||
}
|
||||
else if (declaration.instanceInitializer() != null)
|
||||
{
|
||||
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.staticInitializer() != null)
|
||||
{
|
||||
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.constructorDeclaration() != null)
|
||||
{
|
||||
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
||||
if (constructor != null) result.Members.Add(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<AnnotationMember> BuildAnnotationMembers(Java9Parser.AnnotationTypeBodyContext context)
|
||||
{
|
||||
var members = new List<AnnotationMember>();
|
||||
@@ -1197,7 +1416,7 @@ namespace IronJava.Core.AST.Builders
|
||||
|
||||
if (context.defaultValue() != null)
|
||||
{
|
||||
defaultValue = BuildExpression(context.defaultValue().elementValue());
|
||||
defaultValue = BuildElementValue(context.defaultValue().elementValue());
|
||||
}
|
||||
|
||||
return new AnnotationMember(location, name, type, defaultValue);
|
||||
@@ -2108,7 +2327,9 @@ namespace IronJava.Core.AST.Builders
|
||||
type,
|
||||
new List<TypeReference>(),
|
||||
members,
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2460,46 +2681,6 @@ namespace IronJava.Core.AST.Builders
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private Expression? BuildElementValue(Java9Parser.ElementValueContext context)
|
||||
{
|
||||
if (context.conditionalExpression() != null)
|
||||
{
|
||||
return BuildConditionalExpression(context.conditionalExpression());
|
||||
}
|
||||
else if (context.elementValueArrayInitializer() != null)
|
||||
{
|
||||
return BuildElementValueArrayInitializer(context.elementValueArrayInitializer());
|
||||
}
|
||||
else if (context.annotation() != null)
|
||||
{
|
||||
// Annotation as expression - wrap it
|
||||
var annotation = BuildAnnotation(context.annotation());
|
||||
if (annotation != null)
|
||||
{
|
||||
// Create a special expression to hold the annotation
|
||||
return new IdentifierExpression(annotation.Location, "@" + annotation.Type.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ArrayInitializer? BuildElementValueArrayInitializer(Java9Parser.ElementValueArrayInitializerContext context)
|
||||
{
|
||||
var location = GetSourceRange(context);
|
||||
var elements = new List<Expression>();
|
||||
|
||||
if (context.elementValueList() != null)
|
||||
{
|
||||
foreach (var value in context.elementValueList().elementValue())
|
||||
{
|
||||
var expr = BuildElementValue(value);
|
||||
if (expr != null) elements.Add(expr);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayInitializer(location, elements);
|
||||
}
|
||||
|
||||
// Statement building methods
|
||||
|
||||
@@ -2829,7 +3010,9 @@ namespace IronJava.Core.AST.Builders
|
||||
type,
|
||||
new List<TypeReference>(),
|
||||
members,
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3458,5 +3641,12 @@ namespace IronJava.Core.AST.Builders
|
||||
|
||||
return new JavaDoc(range, content, tags);
|
||||
}
|
||||
|
||||
// Helper classes for building class bodies with both members and nested types
|
||||
private class ClassBodyResult
|
||||
{
|
||||
public List<MemberDeclaration> Members { get; set; } = new List<MemberDeclaration>();
|
||||
public List<TypeDeclaration> NestedTypes { get; set; } = new List<TypeDeclaration>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Comparison
|
||||
namespace MarketAlly.IronJava.Core.AST.Comparison
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides equality comparison for AST nodes.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST
|
||||
namespace MarketAlly.IronJava.Core.AST
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all Java AST nodes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace IronJava.Core.AST
|
||||
namespace MarketAlly.IronJava.Core.AST
|
||||
{
|
||||
/// <summary>
|
||||
/// Java access modifiers and other modifiers as flags.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Java annotation usage.
|
||||
@@ -10,6 +10,11 @@ namespace IronJava.Core.AST.Nodes
|
||||
{
|
||||
public TypeReference Type { get; }
|
||||
public IReadOnlyList<AnnotationArgument> Arguments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the annotation (e.g., "Override" for @Override).
|
||||
/// </summary>
|
||||
public string Name => Type.Name;
|
||||
|
||||
public Annotation(
|
||||
SourceRange location,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Java source file (compilation unit).
|
||||
@@ -38,6 +38,11 @@ namespace IronJava.Core.AST.Nodes
|
||||
{
|
||||
public string PackageName { get; }
|
||||
public IReadOnlyList<Annotation> Annotations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the package name. Alias for PackageName for consistency.
|
||||
/// </summary>
|
||||
public string Name => PackageName;
|
||||
|
||||
public PackageDeclaration(
|
||||
SourceRange location,
|
||||
@@ -61,6 +66,13 @@ namespace IronJava.Core.AST.Nodes
|
||||
public string ImportPath { get; }
|
||||
public bool IsStatic { get; }
|
||||
public bool IsWildcard { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the imported type or package.
|
||||
/// For "import java.util.List", returns "java.util.List"
|
||||
/// For "import java.util.*", returns "java.util.*"
|
||||
/// </summary>
|
||||
public string Name => ImportPath;
|
||||
|
||||
public ImportDeclaration(
|
||||
SourceRange location,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all expressions.
|
||||
@@ -400,6 +400,23 @@ namespace IronJava.Core.AST.Nodes
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitArrayInitializer(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an annotation used as an expression (in annotation element values).
|
||||
/// </summary>
|
||||
public class AnnotationExpression : Expression
|
||||
{
|
||||
public Annotation Annotation { get; }
|
||||
|
||||
public AnnotationExpression(SourceRange location, Annotation annotation) : base(location)
|
||||
{
|
||||
Annotation = annotation;
|
||||
AddChild(annotation);
|
||||
}
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitAnnotationExpression(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitAnnotationExpression(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a lambda expression.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for class/interface members.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all statements.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using System.Linq;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all type declarations (class, interface, enum, annotation).
|
||||
@@ -13,6 +14,11 @@ namespace IronJava.Core.AST.Nodes
|
||||
public IReadOnlyList<Annotation> Annotations { get; }
|
||||
public IReadOnlyList<TypeParameter> TypeParameters { get; }
|
||||
public JavaDoc? JavaDoc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the body/members of this type declaration.
|
||||
/// </summary>
|
||||
public abstract IEnumerable<JavaNode> Body { get; }
|
||||
|
||||
protected TypeDeclaration(
|
||||
SourceRange location,
|
||||
@@ -42,6 +48,7 @@ namespace IronJava.Core.AST.Nodes
|
||||
public TypeReference? SuperClass { get; }
|
||||
public IReadOnlyList<TypeReference> Interfaces { get; }
|
||||
public IReadOnlyList<MemberDeclaration> Members { get; }
|
||||
public IReadOnlyList<TypeDeclaration> NestedTypes { get; }
|
||||
public bool IsRecord { get; }
|
||||
|
||||
public ClassDeclaration(
|
||||
@@ -53,6 +60,7 @@ namespace IronJava.Core.AST.Nodes
|
||||
TypeReference? superClass,
|
||||
IReadOnlyList<TypeReference> interfaces,
|
||||
IReadOnlyList<MemberDeclaration> members,
|
||||
IReadOnlyList<TypeDeclaration> nestedTypes,
|
||||
JavaDoc? javaDoc,
|
||||
bool isRecord = false)
|
||||
: base(location, name, modifiers, annotations, typeParameters, javaDoc)
|
||||
@@ -60,13 +68,17 @@ namespace IronJava.Core.AST.Nodes
|
||||
SuperClass = superClass;
|
||||
Interfaces = interfaces;
|
||||
Members = members;
|
||||
NestedTypes = nestedTypes;
|
||||
IsRecord = isRecord;
|
||||
|
||||
if (superClass != null) AddChild(superClass);
|
||||
AddChildren(interfaces);
|
||||
AddChildren(members);
|
||||
AddChildren(nestedTypes);
|
||||
}
|
||||
|
||||
public override IEnumerable<JavaNode> Body => Members.Cast<JavaNode>().Concat(NestedTypes);
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitClassDeclaration(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitClassDeclaration(this);
|
||||
}
|
||||
@@ -78,6 +90,7 @@ namespace IronJava.Core.AST.Nodes
|
||||
{
|
||||
public IReadOnlyList<TypeReference> ExtendedInterfaces { get; }
|
||||
public IReadOnlyList<MemberDeclaration> Members { get; }
|
||||
public IReadOnlyList<TypeDeclaration> NestedTypes { get; }
|
||||
|
||||
public InterfaceDeclaration(
|
||||
SourceRange location,
|
||||
@@ -87,16 +100,21 @@ namespace IronJava.Core.AST.Nodes
|
||||
IReadOnlyList<TypeParameter> typeParameters,
|
||||
IReadOnlyList<TypeReference> extendedInterfaces,
|
||||
IReadOnlyList<MemberDeclaration> members,
|
||||
IReadOnlyList<TypeDeclaration> nestedTypes,
|
||||
JavaDoc? javaDoc)
|
||||
: base(location, name, modifiers, annotations, typeParameters, javaDoc)
|
||||
{
|
||||
ExtendedInterfaces = extendedInterfaces;
|
||||
Members = members;
|
||||
NestedTypes = nestedTypes;
|
||||
|
||||
AddChildren(extendedInterfaces);
|
||||
AddChildren(members);
|
||||
AddChildren(nestedTypes);
|
||||
}
|
||||
|
||||
public override IEnumerable<JavaNode> Body => Members.Cast<JavaNode>().Concat(NestedTypes);
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitInterfaceDeclaration(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitInterfaceDeclaration(this);
|
||||
}
|
||||
@@ -109,6 +127,7 @@ namespace IronJava.Core.AST.Nodes
|
||||
public IReadOnlyList<TypeReference> Interfaces { get; }
|
||||
public IReadOnlyList<EnumConstant> Constants { get; }
|
||||
public IReadOnlyList<MemberDeclaration> Members { get; }
|
||||
public IReadOnlyList<TypeDeclaration> NestedTypes { get; }
|
||||
|
||||
public EnumDeclaration(
|
||||
SourceRange location,
|
||||
@@ -118,18 +137,23 @@ namespace IronJava.Core.AST.Nodes
|
||||
IReadOnlyList<TypeReference> interfaces,
|
||||
IReadOnlyList<EnumConstant> constants,
|
||||
IReadOnlyList<MemberDeclaration> members,
|
||||
IReadOnlyList<TypeDeclaration> nestedTypes,
|
||||
JavaDoc? javaDoc)
|
||||
: base(location, name, modifiers, annotations, new List<TypeParameter>(), javaDoc)
|
||||
{
|
||||
Interfaces = interfaces;
|
||||
Constants = constants;
|
||||
Members = members;
|
||||
NestedTypes = nestedTypes;
|
||||
|
||||
AddChildren(interfaces);
|
||||
AddChildren(constants);
|
||||
AddChildren(members);
|
||||
AddChildren(nestedTypes);
|
||||
}
|
||||
|
||||
public override IEnumerable<JavaNode> Body => Constants.Cast<JavaNode>().Concat(Members).Concat(NestedTypes);
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitEnumDeclaration(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitEnumDeclaration(this);
|
||||
}
|
||||
@@ -140,6 +164,7 @@ namespace IronJava.Core.AST.Nodes
|
||||
public class AnnotationDeclaration : TypeDeclaration
|
||||
{
|
||||
public IReadOnlyList<AnnotationMember> Members { get; }
|
||||
public IReadOnlyList<TypeDeclaration> NestedTypes { get; }
|
||||
|
||||
public AnnotationDeclaration(
|
||||
SourceRange location,
|
||||
@@ -147,13 +172,18 @@ namespace IronJava.Core.AST.Nodes
|
||||
Modifiers modifiers,
|
||||
IReadOnlyList<Annotation> annotations,
|
||||
IReadOnlyList<AnnotationMember> members,
|
||||
IReadOnlyList<TypeDeclaration> nestedTypes,
|
||||
JavaDoc? javaDoc)
|
||||
: base(location, name, modifiers, annotations, new List<TypeParameter>(), javaDoc)
|
||||
{
|
||||
Members = members;
|
||||
NestedTypes = nestedTypes;
|
||||
AddChildren(members);
|
||||
AddChildren(nestedTypes);
|
||||
}
|
||||
|
||||
public override IEnumerable<JavaNode> Body => Members.Cast<JavaNode>().Concat(NestedTypes);
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitAnnotationDeclaration(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitAnnotationDeclaration(this);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Nodes
|
||||
namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a reference to a type.
|
||||
@@ -9,6 +9,16 @@ namespace IronJava.Core.AST.Nodes
|
||||
public abstract class TypeReference : JavaNode
|
||||
{
|
||||
protected TypeReference(SourceRange location) : base(location) { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the simple name of the type.
|
||||
/// </summary>
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the fully qualified name of the type.
|
||||
/// </summary>
|
||||
public virtual string QualifiedName => Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -17,6 +27,8 @@ namespace IronJava.Core.AST.Nodes
|
||||
public class PrimitiveType : TypeReference
|
||||
{
|
||||
public PrimitiveTypeKind Kind { get; }
|
||||
|
||||
public override string Name => Kind.ToString().ToLower();
|
||||
|
||||
public PrimitiveType(SourceRange location, PrimitiveTypeKind kind) : base(location)
|
||||
{
|
||||
@@ -45,7 +57,9 @@ namespace IronJava.Core.AST.Nodes
|
||||
/// </summary>
|
||||
public class ClassOrInterfaceType : TypeReference
|
||||
{
|
||||
public string Name { get; }
|
||||
private readonly string _name;
|
||||
|
||||
public override string Name => _name;
|
||||
public ClassOrInterfaceType? Scope { get; }
|
||||
public IReadOnlyList<TypeArgument> TypeArguments { get; }
|
||||
public IReadOnlyList<Annotation> Annotations { get; }
|
||||
@@ -57,7 +71,7 @@ namespace IronJava.Core.AST.Nodes
|
||||
IReadOnlyList<TypeArgument> typeArguments,
|
||||
IReadOnlyList<Annotation> annotations) : base(location)
|
||||
{
|
||||
Name = name;
|
||||
_name = name;
|
||||
Scope = scope;
|
||||
TypeArguments = typeArguments;
|
||||
Annotations = annotations;
|
||||
@@ -68,6 +82,8 @@ namespace IronJava.Core.AST.Nodes
|
||||
}
|
||||
|
||||
public string FullName => Scope != null ? $"{Scope.FullName}.{Name}" : Name;
|
||||
|
||||
public override string QualifiedName => FullName;
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitClassOrInterfaceType(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitClassOrInterfaceType(this);
|
||||
@@ -80,6 +96,10 @@ namespace IronJava.Core.AST.Nodes
|
||||
{
|
||||
public TypeReference ElementType { get; }
|
||||
public int Dimensions { get; }
|
||||
|
||||
public override string Name => ElementType.Name + new string('[', Dimensions) + new string(']', Dimensions);
|
||||
|
||||
public override string QualifiedName => ElementType.QualifiedName + new string('[', Dimensions) + new string(']', Dimensions);
|
||||
|
||||
public ArrayType(
|
||||
SourceRange location,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Query
|
||||
namespace MarketAlly.IronJava.Core.AST.Query
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides LINQ-style querying capabilities for AST nodes.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace IronJava.Core.AST
|
||||
namespace MarketAlly.IronJava.Core.AST
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a location in the source code.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.AST.Transformation
|
||||
namespace MarketAlly.IronJava.Core.AST.Transformation
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for AST transformations that create modified copies of nodes.
|
||||
@@ -149,6 +149,7 @@ namespace IronJava.Core.AST.Transformation
|
||||
node.SuperClass,
|
||||
node.Interfaces,
|
||||
transformedMembers,
|
||||
node.NestedTypes,
|
||||
node.JavaDoc,
|
||||
node.IsRecord
|
||||
);
|
||||
@@ -201,6 +202,7 @@ namespace IronJava.Core.AST.Transformation
|
||||
node.SuperClass,
|
||||
node.Interfaces,
|
||||
transformedMembers,
|
||||
node.NestedTypes,
|
||||
node.JavaDoc,
|
||||
node.IsRecord
|
||||
);
|
||||
@@ -336,6 +338,7 @@ namespace IronJava.Core.AST.Transformation
|
||||
node.SuperClass,
|
||||
node.Interfaces,
|
||||
transformedMembers,
|
||||
node.NestedTypes,
|
||||
node.JavaDoc,
|
||||
node.IsRecord
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
|
||||
namespace IronJava.Core.AST.Visitors
|
||||
namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Example visitor that collects all class names in the AST.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
|
||||
namespace IronJava.Core.AST.Visitors
|
||||
namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Visitor interface for traversing Java AST nodes without returning values.
|
||||
@@ -51,6 +51,7 @@ namespace IronJava.Core.AST.Visitors
|
||||
void VisitNewExpression(NewExpression node);
|
||||
void VisitNewArrayExpression(NewArrayExpression node);
|
||||
void VisitArrayInitializer(ArrayInitializer node);
|
||||
void VisitAnnotationExpression(AnnotationExpression node);
|
||||
void VisitLambdaExpression(LambdaExpression node);
|
||||
void VisitLambdaParameter(LambdaParameter node);
|
||||
void VisitMethodReferenceExpression(MethodReferenceExpression node);
|
||||
@@ -135,6 +136,7 @@ namespace IronJava.Core.AST.Visitors
|
||||
T VisitNewExpression(NewExpression node);
|
||||
T VisitNewArrayExpression(NewArrayExpression node);
|
||||
T VisitArrayInitializer(ArrayInitializer node);
|
||||
T VisitAnnotationExpression(AnnotationExpression node);
|
||||
T VisitLambdaExpression(LambdaExpression node);
|
||||
T VisitLambdaParameter(LambdaParameter node);
|
||||
T VisitMethodReferenceExpression(MethodReferenceExpression node);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
|
||||
namespace IronJava.Core.AST.Visitors
|
||||
namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
/// Base implementation of IJavaVisitor that visits all child nodes by default.
|
||||
@@ -54,6 +54,7 @@ namespace IronJava.Core.AST.Visitors
|
||||
public virtual void VisitNewExpression(NewExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitArrayInitializer(ArrayInitializer node) => DefaultVisit(node);
|
||||
public virtual void VisitAnnotationExpression(AnnotationExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitLambdaExpression(LambdaExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
||||
public virtual void VisitMethodReferenceExpression(MethodReferenceExpression node) => DefaultVisit(node);
|
||||
@@ -133,6 +134,7 @@ namespace IronJava.Core.AST.Visitors
|
||||
public virtual T VisitNewExpression(NewExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitArrayInitializer(ArrayInitializer node) => DefaultVisit(node);
|
||||
public virtual T VisitAnnotationExpression(AnnotationExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitLambdaExpression(LambdaExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
||||
public virtual T VisitMethodReferenceExpression(MethodReferenceExpression node) => DefaultVisit(node);
|
||||
|
||||
@@ -35,7 +35,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IronJava.Core.Grammar
|
||||
namespace MarketAlly.IronJava.Core.Grammar
|
||||
{
|
||||
public abstract class Java9LexerBase : Lexer
|
||||
{
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>MarketAlly.IronJava</RootNamespace>
|
||||
|
||||
<!-- NuGet Package Metadata -->
|
||||
<PackageId>IronJava</PackageId>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>2.1.2</Version>
|
||||
<Authors>David H Friedel Jr</Authors>
|
||||
<Company>MarketAlly</Company>
|
||||
<Title>MarketAlly IronJava</Title>
|
||||
<Title>IronJava</Title>
|
||||
<Description>A native .NET library that parses Java source files and provides a strongly-typed AST (Abstract Syntax Tree) accessible in C#. Supports Java 17 syntax with comprehensive visitor pattern, AST transformations, and JSON serialization.</Description>
|
||||
<PackageTags>java;parser;ast;antlr;syntax-tree;java17;code-analysis;visitor-pattern</PackageTags>
|
||||
<PackageProjectUrl>https://github.com/MarketAlly/IronJava</PackageProjectUrl>
|
||||
@@ -53,10 +54,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Antlr4 Include="Grammar\Java9Lexer.g4">
|
||||
<Package>IronJava.Core.Grammar</Package>
|
||||
<Package>MarketAlly.IronJava.Core.Grammar</Package>
|
||||
</Antlr4>
|
||||
<Antlr4 Include="Grammar\Java9Parser.g4">
|
||||
<Package>IronJava.Core.Grammar</Package>
|
||||
<Package>MarketAlly.IronJava.Core.Grammar</Package>
|
||||
<Listener>false</Listener>
|
||||
<Visitor>true</Visitor>
|
||||
</Antlr4>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Antlr4.Runtime;
|
||||
using IronJava.Core.AST.Builders;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.Grammar;
|
||||
using MarketAlly.IronJava.Core.AST.Builders;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.Grammar;
|
||||
|
||||
namespace IronJava.Core
|
||||
namespace MarketAlly.IronJava.Core
|
||||
{
|
||||
public class JavaParser
|
||||
{
|
||||
|
||||
@@ -3,11 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
|
||||
namespace IronJava.Core.Serialization
|
||||
namespace MarketAlly.IronJava.Core.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides JSON serialization for Java AST nodes.
|
||||
@@ -154,6 +154,7 @@ namespace IronJava.Core.Serialization
|
||||
result["superClass"] = node.SuperClass?.Accept(this);
|
||||
result["interfaces"] = node.Interfaces.Select(i => i.Accept(this)).ToList();
|
||||
result["members"] = node.Members.Select(m => m.Accept(this)).ToList();
|
||||
result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList();
|
||||
result["isRecord"] = node.IsRecord;
|
||||
return result;
|
||||
}
|
||||
@@ -163,6 +164,7 @@ namespace IronJava.Core.Serialization
|
||||
var result = CreateTypeDeclarationBase(node);
|
||||
result["extendedInterfaces"] = node.ExtendedInterfaces.Select(i => i.Accept(this)).ToList();
|
||||
result["members"] = node.Members.Select(m => m.Accept(this)).ToList();
|
||||
result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -172,6 +174,7 @@ namespace IronJava.Core.Serialization
|
||||
result["interfaces"] = node.Interfaces.Select(i => i.Accept(this)).ToList();
|
||||
result["constants"] = node.Constants.Select(c => c.Accept(this)).ToList();
|
||||
result["members"] = node.Members.Select(m => m.Accept(this)).ToList();
|
||||
result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -179,6 +182,7 @@ namespace IronJava.Core.Serialization
|
||||
{
|
||||
var result = CreateTypeDeclarationBase(node);
|
||||
result["members"] = node.Members.Select(m => m.Accept(this)).ToList();
|
||||
result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -412,6 +416,22 @@ namespace IronJava.Core.Serialization
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitAnnotationValueArgument(AnnotationValueArgument node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
result["name"] = node.Name;
|
||||
result["value"] = node.Value.Accept(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitAnnotationArrayArgument(AnnotationArrayArgument node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
result["name"] = node.Name;
|
||||
result["values"] = node.Values.Select(v => v.Accept(this)).ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitJavaDoc(JavaDoc node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
@@ -557,6 +577,13 @@ namespace IronJava.Core.Serialization
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitAnnotationExpression(AnnotationExpression node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
result["annotation"] = node.Annotation.Accept(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitMethodReferenceExpression(MethodReferenceExpression node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
@@ -743,6 +770,9 @@ namespace IronJava.Core.Serialization
|
||||
"InstanceOfExpression" => DeserializeInstanceOfExpression(element, location),
|
||||
"NewArrayExpression" => DeserializeNewArrayExpression(element, location),
|
||||
"ArrayInitializer" => DeserializeArrayInitializer(element, location),
|
||||
"AnnotationExpression" => DeserializeAnnotationExpression(element, location),
|
||||
"AnnotationValueArgument" => DeserializeAnnotationValueArgument(element, location),
|
||||
"AnnotationArrayArgument" => DeserializeAnnotationArrayArgument(element, location),
|
||||
"MethodReferenceExpression" => DeserializeMethodReferenceExpression(element, location),
|
||||
"ClassLiteralExpression" => DeserializeClassLiteralExpression(element, location),
|
||||
"LocalVariableStatement" => DeserializeLocalVariableStatement(element, location),
|
||||
@@ -829,9 +859,14 @@ namespace IronJava.Core.Serialization
|
||||
|
||||
var interfaces = DeserializeList<ClassOrInterfaceType>(element.GetProperty("interfaces"));
|
||||
var members = DeserializeList<MemberDeclaration>(element.GetProperty("members"));
|
||||
var isRecord = element.GetProperty("isRecord").GetBoolean();
|
||||
var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl)
|
||||
? DeserializeList<TypeDeclaration>(nestedTypesEl)
|
||||
: new List<TypeDeclaration>();
|
||||
var isRecord = element.TryGetProperty("isRecord", out var isRecordEl)
|
||||
? isRecordEl.GetBoolean()
|
||||
: false;
|
||||
|
||||
return new ClassDeclaration(location, name, modifiers, annotations, typeParameters, superClass, interfaces, members, javaDoc, isRecord);
|
||||
return new ClassDeclaration(location, name, modifiers, annotations, typeParameters, superClass, interfaces, members, nestedTypes, javaDoc, isRecord);
|
||||
}
|
||||
|
||||
private InterfaceDeclaration DeserializeInterfaceDeclaration(JsonElement element, SourceRange location)
|
||||
@@ -846,8 +881,11 @@ namespace IronJava.Core.Serialization
|
||||
|
||||
var extendedInterfaces = DeserializeList<ClassOrInterfaceType>(element.GetProperty("extendedInterfaces"));
|
||||
var members = DeserializeList<MemberDeclaration>(element.GetProperty("members"));
|
||||
var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl)
|
||||
? DeserializeList<TypeDeclaration>(nestedTypesEl)
|
||||
: new List<TypeDeclaration>();
|
||||
|
||||
return new InterfaceDeclaration(location, name, modifiers, annotations, typeParameters, extendedInterfaces, members, javaDoc);
|
||||
return new InterfaceDeclaration(location, name, modifiers, annotations, typeParameters, extendedInterfaces, members, nestedTypes, javaDoc);
|
||||
}
|
||||
|
||||
private EnumDeclaration DeserializeEnumDeclaration(JsonElement element, SourceRange location)
|
||||
@@ -862,8 +900,11 @@ namespace IronJava.Core.Serialization
|
||||
var interfaces = DeserializeList<ClassOrInterfaceType>(element.GetProperty("interfaces"));
|
||||
var constants = DeserializeList<EnumConstant>(element.GetProperty("constants"));
|
||||
var members = DeserializeList<MemberDeclaration>(element.GetProperty("members"));
|
||||
var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl)
|
||||
? DeserializeList<TypeDeclaration>(nestedTypesEl)
|
||||
: new List<TypeDeclaration>();
|
||||
|
||||
return new EnumDeclaration(location, name, modifiers, annotations, interfaces, constants, members, javaDoc);
|
||||
return new EnumDeclaration(location, name, modifiers, annotations, interfaces, constants, members, nestedTypes, javaDoc);
|
||||
}
|
||||
|
||||
private AnnotationDeclaration DeserializeAnnotationDeclaration(JsonElement element, SourceRange location)
|
||||
@@ -876,8 +917,11 @@ namespace IronJava.Core.Serialization
|
||||
: null;
|
||||
|
||||
var members = DeserializeList<AnnotationMember>(element.GetProperty("members"));
|
||||
var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl)
|
||||
? DeserializeList<TypeDeclaration>(nestedTypesEl)
|
||||
: new List<TypeDeclaration>();
|
||||
|
||||
return new AnnotationDeclaration(location, name, modifiers, annotations, members, javaDoc);
|
||||
return new AnnotationDeclaration(location, name, modifiers, annotations, members, nestedTypes, javaDoc);
|
||||
}
|
||||
|
||||
private FieldDeclaration DeserializeFieldDeclaration(JsonElement element, SourceRange location)
|
||||
@@ -1264,6 +1308,30 @@ namespace IronJava.Core.Serialization
|
||||
return new ArrayInitializer(location, elements);
|
||||
}
|
||||
|
||||
private AnnotationExpression DeserializeAnnotationExpression(JsonElement element, SourceRange location)
|
||||
{
|
||||
var annotation = Deserialize(element.GetProperty("annotation")) as Annotation ?? throw new JsonException("annotation is not Annotation");
|
||||
return new AnnotationExpression(location, annotation);
|
||||
}
|
||||
|
||||
private AnnotationValueArgument DeserializeAnnotationValueArgument(JsonElement element, SourceRange location)
|
||||
{
|
||||
var name = element.TryGetProperty("name", out var nameEl) && nameEl.ValueKind != JsonValueKind.Null
|
||||
? nameEl.GetString()
|
||||
: null;
|
||||
var value = Deserialize(element.GetProperty("value")) as Expression ?? throw new JsonException("value is not Expression");
|
||||
return new AnnotationValueArgument(location, name, value);
|
||||
}
|
||||
|
||||
private AnnotationArrayArgument DeserializeAnnotationArrayArgument(JsonElement element, SourceRange location)
|
||||
{
|
||||
var name = element.TryGetProperty("name", out var nameEl) && nameEl.ValueKind != JsonValueKind.Null
|
||||
? nameEl.GetString()
|
||||
: null;
|
||||
var values = DeserializeList<Expression>(element.GetProperty("values"));
|
||||
return new AnnotationArrayArgument(location, name, values);
|
||||
}
|
||||
|
||||
private MethodReferenceExpression DeserializeMethodReferenceExpression(JsonElement element, SourceRange location)
|
||||
{
|
||||
var target = Deserialize(element.GetProperty("target")) as Expression ?? throw new JsonException("target is not Expression");
|
||||
|
||||
215
IronJava.Tests/AnnotationParsingTests.cs
Normal file
215
IronJava.Tests/AnnotationParsingTests.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System.Linq;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Query;
|
||||
using Xunit;
|
||||
|
||||
namespace MarketAlly.IronJava.Tests
|
||||
{
|
||||
public class AnnotationParsingTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestClassAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
@Entity
|
||||
@Table(name = ""users"")
|
||||
public class User {
|
||||
private String name;
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var userClass = result.Ast.Types.OfType<ClassDeclaration>().FirstOrDefault();
|
||||
Assert.NotNull(userClass);
|
||||
Assert.Equal("User", userClass.Name);
|
||||
|
||||
// Check annotations
|
||||
Assert.Equal(2, userClass.Annotations.Count);
|
||||
|
||||
var entityAnnotation = userClass.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Entity");
|
||||
Assert.NotNull(entityAnnotation);
|
||||
Assert.Empty(entityAnnotation.Arguments);
|
||||
|
||||
var tableAnnotation = userClass.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Table");
|
||||
Assert.NotNull(tableAnnotation);
|
||||
Assert.Single(tableAnnotation.Arguments);
|
||||
|
||||
var nameArg = tableAnnotation.Arguments[0] as AnnotationValueArgument;
|
||||
Assert.NotNull(nameArg);
|
||||
Assert.Equal("name", nameArg.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestMethodAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class UserService {
|
||||
@GetMapping(""/users/{id}"")
|
||||
@ResponseBody
|
||||
public User getUser(@PathVariable Long id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var method = AstQuery.FindFirst<MethodDeclaration>(result.Ast);
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal("getUser", method.Name);
|
||||
|
||||
// Check method annotations
|
||||
Assert.Equal(2, method.Annotations.Count);
|
||||
|
||||
var getMappingAnnotation = method.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "GetMapping");
|
||||
Assert.NotNull(getMappingAnnotation);
|
||||
Assert.Single(getMappingAnnotation.Arguments);
|
||||
|
||||
var responseBodyAnnotation = method.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "ResponseBody");
|
||||
Assert.NotNull(responseBodyAnnotation);
|
||||
Assert.Empty(responseBodyAnnotation.Arguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFieldAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var fields = AstQuery.FindAll<FieldDeclaration>(result.Ast).ToList();
|
||||
Assert.Equal(2, fields.Count);
|
||||
|
||||
// Check id field annotations
|
||||
var idField = fields.FirstOrDefault(f => f.Variables[0].Name == "id");
|
||||
Assert.NotNull(idField);
|
||||
Assert.Equal(2, idField.Annotations.Count);
|
||||
|
||||
var idAnnotation = idField.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Id");
|
||||
Assert.NotNull(idAnnotation);
|
||||
|
||||
var generatedValueAnnotation = idField.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "GeneratedValue");
|
||||
Assert.NotNull(generatedValueAnnotation);
|
||||
Assert.Single(generatedValueAnnotation.Arguments);
|
||||
|
||||
// Check name field annotations
|
||||
var nameField = fields.FirstOrDefault(f => f.Variables[0].Name == "name");
|
||||
Assert.NotNull(nameField);
|
||||
Assert.Single(nameField.Annotations);
|
||||
|
||||
var columnAnnotation = nameField.Annotations[0];
|
||||
Assert.Equal("Column", ((ClassOrInterfaceType)columnAnnotation.Type).Name);
|
||||
Assert.Equal(2, columnAnnotation.Arguments.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestParameterAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class UserController {
|
||||
public void updateUser(@RequestBody User user, @PathVariable Long id) {
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var method = AstQuery.FindFirst<MethodDeclaration>(result.Ast);
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal(2, method.Parameters.Count);
|
||||
|
||||
// Check first parameter annotations
|
||||
var userParam = method.Parameters[0];
|
||||
Assert.Equal("user", userParam.Name);
|
||||
Assert.Single(userParam.Annotations);
|
||||
Assert.Equal("RequestBody", ((ClassOrInterfaceType)userParam.Annotations[0].Type).Name);
|
||||
|
||||
// Check second parameter annotations
|
||||
var idParam = method.Parameters[1];
|
||||
Assert.Equal("id", idParam.Name);
|
||||
Assert.Single(idParam.Annotations);
|
||||
Assert.Equal("PathVariable", ((ClassOrInterfaceType)idParam.Annotations[0].Type).Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestNestedAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface MyAnnotation {
|
||||
String value() default ""default"";
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var annotationDecl = result.Ast.Types.OfType<AnnotationDeclaration>().FirstOrDefault();
|
||||
Assert.NotNull(annotationDecl);
|
||||
Assert.Equal("MyAnnotation", annotationDecl.Name);
|
||||
|
||||
// Check meta-annotations
|
||||
Assert.Equal(2, annotationDecl.Annotations.Count);
|
||||
|
||||
var targetAnnotation = annotationDecl.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Target");
|
||||
Assert.NotNull(targetAnnotation);
|
||||
Assert.Single(targetAnnotation.Arguments);
|
||||
|
||||
var retentionAnnotation = annotationDecl.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Retention");
|
||||
Assert.NotNull(retentionAnnotation);
|
||||
Assert.Single(retentionAnnotation.Arguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAnnotationArrayValues()
|
||||
{
|
||||
var javaCode = @"
|
||||
@SuppressWarnings({""unchecked"", ""rawtypes""})
|
||||
public class Test {
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var testClass = result.Ast.Types.OfType<ClassDeclaration>().FirstOrDefault();
|
||||
Assert.NotNull(testClass);
|
||||
Assert.Single(testClass.Annotations);
|
||||
|
||||
var suppressWarningsAnnotation = testClass.Annotations[0];
|
||||
Assert.Equal("SuppressWarnings", ((ClassOrInterfaceType)suppressWarningsAnnotation.Type).Name);
|
||||
Assert.Single(suppressWarningsAnnotation.Arguments);
|
||||
|
||||
var valueArg = suppressWarningsAnnotation.Arguments[0] as AnnotationValueArgument;
|
||||
Assert.NotNull(valueArg);
|
||||
Assert.Equal("value", valueArg.Name);
|
||||
|
||||
// The value should be an ArrayInitializer expression
|
||||
var arrayInit = valueArg.Value as ArrayInitializer;
|
||||
Assert.NotNull(arrayInit);
|
||||
Assert.Equal(2, arrayInit.Elements.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Comparison;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Query;
|
||||
using IronJava.Core.AST.Transformation;
|
||||
using IronJava.Core.Serialization;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Comparison;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Query;
|
||||
using MarketAlly.IronJava.Core.AST.Transformation;
|
||||
using MarketAlly.IronJava.Core.Serialization;
|
||||
using Xunit;
|
||||
|
||||
namespace IronJava.Tests
|
||||
namespace MarketAlly.IronJava.Tests
|
||||
{
|
||||
public class Phase3Tests
|
||||
{
|
||||
@@ -246,7 +246,9 @@ namespace IronJava.Tests
|
||||
null
|
||||
)
|
||||
},
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
var builder = new TransformationBuilder()
|
||||
@@ -348,7 +350,9 @@ namespace IronJava.Tests
|
||||
null,
|
||||
new List<TypeReference>(),
|
||||
new List<MemberDeclaration> { mainMethod, helperMethod, field },
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
return new CompilationUnit(
|
||||
@@ -393,7 +397,9 @@ namespace IronJava.Tests
|
||||
null,
|
||||
new List<TypeReference> { serializableInterface },
|
||||
new List<MemberDeclaration> { serializeMethod },
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
return new CompilationUnit(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
using Xunit;
|
||||
|
||||
namespace IronJava.Tests
|
||||
namespace MarketAlly.IronJava.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Demonstrates Phase 2 functionality with our typed AST.
|
||||
@@ -55,7 +55,9 @@ namespace IronJava.Tests
|
||||
null,
|
||||
new List<TypeReference>(),
|
||||
new List<MemberDeclaration> { mainMethod },
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
var compilationUnit = new CompilationUnit(
|
||||
@@ -137,7 +139,9 @@ namespace IronJava.Tests
|
||||
null,
|
||||
new List<TypeReference>(),
|
||||
new List<MemberDeclaration>(),
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
var outerClass = new ClassDeclaration(
|
||||
@@ -149,7 +153,9 @@ namespace IronJava.Tests
|
||||
null,
|
||||
new List<TypeReference>(),
|
||||
new List<MemberDeclaration>(),
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
// Navigate the AST
|
||||
@@ -194,7 +200,9 @@ namespace IronJava.Tests
|
||||
null,
|
||||
new List<TypeReference>(),
|
||||
new List<MemberDeclaration> { field },
|
||||
null
|
||||
new List<TypeDeclaration>(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
var compilationUnit = new CompilationUnit(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using Xunit;
|
||||
|
||||
namespace IronJava.Tests
|
||||
namespace MarketAlly.IronJava.Tests
|
||||
{
|
||||
public class BasicParsingTests
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>MarketAlly.IronJava.Tests</RootNamespace>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.Serialization;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.Serialization;
|
||||
using Xunit;
|
||||
|
||||
namespace IronJava.Tests
|
||||
namespace MarketAlly.IronJava.Tests
|
||||
{
|
||||
public class JsonDeserializationTests
|
||||
{
|
||||
|
||||
21
README.md
21
README.md
@@ -39,9 +39,9 @@ Install-Package IronJava
|
||||
## Quick Start
|
||||
|
||||
```csharp
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Query;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Query;
|
||||
|
||||
// Parse Java source code
|
||||
var parser = new JavaParser();
|
||||
@@ -82,9 +82,17 @@ CompilationUnit
|
||||
├── ImportDeclaration[]
|
||||
└── TypeDeclaration[]
|
||||
├── ClassDeclaration
|
||||
│ ├── Members[]
|
||||
│ └── NestedTypes[]
|
||||
├── InterfaceDeclaration
|
||||
│ ├── Members[]
|
||||
│ └── NestedTypes[]
|
||||
├── EnumDeclaration
|
||||
│ ├── Constants[]
|
||||
│ ├── Members[]
|
||||
│ └── NestedTypes[]
|
||||
└── AnnotationDeclaration
|
||||
└── Members[]
|
||||
```
|
||||
|
||||
### Visitor Pattern
|
||||
@@ -152,6 +160,13 @@ var serializableClasses = ast
|
||||
var getters = ast
|
||||
.FindAll<MethodDeclaration>()
|
||||
.Where(m => m.IsGetter());
|
||||
|
||||
// Access nested types
|
||||
var outerClass = ast.Types.OfType<ClassDeclaration>().First();
|
||||
foreach (var nestedType in outerClass.NestedTypes)
|
||||
{
|
||||
Console.WriteLine($"Nested: {nestedType.Name} ({nestedType.GetType().Name})");
|
||||
}
|
||||
```
|
||||
|
||||
### JSON Serialization
|
||||
|
||||
58
TestNestedTypes.cs
Normal file
58
TestNestedTypes.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
|
||||
class TestNestedTypes
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class OuterClass {
|
||||
private int outerField;
|
||||
|
||||
public class InnerClass {
|
||||
private String innerField;
|
||||
|
||||
public void innerMethod() {
|
||||
System.out.println(innerField);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StaticNestedClass {
|
||||
private static int staticField;
|
||||
}
|
||||
|
||||
public interface NestedInterface {
|
||||
void doSomething();
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
Console.WriteLine("Parse successful!");
|
||||
var outerClass = result.Ast.Types[0] as ClassDeclaration;
|
||||
if (outerClass != null)
|
||||
{
|
||||
Console.WriteLine($"Outer class: {outerClass.Name}");
|
||||
Console.WriteLine($"Number of members: {outerClass.Members.Count}");
|
||||
Console.WriteLine($"Number of nested types: {outerClass.NestedTypes.Count}");
|
||||
|
||||
foreach (var nestedType in outerClass.NestedTypes)
|
||||
{
|
||||
Console.WriteLine($" - Nested type: {nestedType.Name} ({nestedType.GetType().Name})");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Parse failed!");
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
Console.WriteLine($"Error: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>MarketAlly.IronJava.Sample</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using IronJava.Core;
|
||||
using IronJava.Core.AST;
|
||||
using IronJava.Core.AST.Nodes;
|
||||
using IronJava.Core.AST.Query;
|
||||
using IronJava.Core.AST.Transformation;
|
||||
using IronJava.Core.AST.Visitors;
|
||||
using IronJava.Core.Serialization;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Query;
|
||||
using MarketAlly.IronJava.Core.AST.Transformation;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.Serialization;
|
||||
|
||||
namespace IronJava.Sample
|
||||
{
|
||||
@@ -15,6 +15,15 @@ namespace IronJava.Sample
|
||||
Console.WriteLine("IronJava Sample Application");
|
||||
Console.WriteLine("===========================\n");
|
||||
|
||||
// Test nested types
|
||||
TestNestedTypes();
|
||||
Console.WriteLine("\n===========================\n");
|
||||
|
||||
// Test annotations
|
||||
TestAnnotations();
|
||||
Console.WriteLine("\n===========================\n");
|
||||
|
||||
|
||||
// Sample Java code
|
||||
string javaCode = @"
|
||||
package com.example;
|
||||
@@ -219,6 +228,171 @@ class User {
|
||||
Console.WriteLine($"\nMethods that throw exceptions: {throwingMethods.Count}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
static void TestNestedTypes()
|
||||
{
|
||||
Console.WriteLine("Testing Nested Types Feature");
|
||||
Console.WriteLine("----------------------------");
|
||||
|
||||
var javaCode = @"
|
||||
public class OuterClass {
|
||||
private int outerField;
|
||||
|
||||
public class InnerClass {
|
||||
private String innerField;
|
||||
|
||||
public void innerMethod() {
|
||||
System.out.println(innerField);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StaticNestedClass {
|
||||
private static int staticField;
|
||||
}
|
||||
|
||||
public interface NestedInterface {
|
||||
void doSomething();
|
||||
}
|
||||
|
||||
public enum NestedEnum {
|
||||
VALUE1, VALUE2
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
Console.WriteLine("✓ Parse successful!");
|
||||
var outerClass = result.Ast!.Types[0] as ClassDeclaration;
|
||||
if (outerClass != null)
|
||||
{
|
||||
Console.WriteLine($"\nOuter class: {outerClass.Name}");
|
||||
Console.WriteLine($" Members: {outerClass.Members.Count}");
|
||||
Console.WriteLine($" Nested types: {outerClass.NestedTypes.Count}");
|
||||
|
||||
foreach (var member in outerClass.Members)
|
||||
{
|
||||
if (member is FieldDeclaration field)
|
||||
{
|
||||
Console.WriteLine($" - Field: {field.Variables[0].Name}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var nestedType in outerClass.NestedTypes)
|
||||
{
|
||||
Console.WriteLine($" - Nested: {nestedType.Name} ({nestedType.GetType().Name})");
|
||||
|
||||
if (nestedType is ClassDeclaration nestedClass)
|
||||
{
|
||||
Console.WriteLine($" Static: {nestedClass.Modifiers.HasFlag(Modifiers.Static)}");
|
||||
Console.WriteLine($" Members: {nestedClass.Members.Count}");
|
||||
}
|
||||
else if (nestedType is EnumDeclaration nestedEnum)
|
||||
{
|
||||
Console.WriteLine($" Constants: {nestedEnum.Constants.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("✗ Parse failed!");
|
||||
}
|
||||
}
|
||||
|
||||
static void TestAnnotations()
|
||||
{
|
||||
Console.WriteLine("Testing Annotation Parsing");
|
||||
Console.WriteLine("--------------------------");
|
||||
|
||||
var javaCode = @"
|
||||
@Entity
|
||||
@Table(name = ""users"")
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@GetMapping(""/users/{id}"")
|
||||
@ResponseBody
|
||||
public User getUser(@PathVariable Long id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
Console.WriteLine("✓ Parse successful!");
|
||||
|
||||
var userClass = result.Ast!.Types[0] as ClassDeclaration;
|
||||
if (userClass != null)
|
||||
{
|
||||
Console.WriteLine($"\nClass: {userClass.Name}");
|
||||
Console.WriteLine($" Class annotations: {userClass.Annotations.Count}");
|
||||
foreach (var annotation in userClass.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName} with {annotation.Arguments.Count} arguments");
|
||||
}
|
||||
|
||||
// Check fields
|
||||
var fields = userClass.Members.OfType<FieldDeclaration>().ToList();
|
||||
Console.WriteLine($"\n Fields: {fields.Count}");
|
||||
foreach (var field in fields)
|
||||
{
|
||||
Console.WriteLine($" - {field.Variables[0].Name}: {field.Annotations.Count} annotations");
|
||||
foreach (var annotation in field.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName}");
|
||||
}
|
||||
}
|
||||
|
||||
// Check methods
|
||||
var methods = userClass.Members.OfType<MethodDeclaration>().ToList();
|
||||
Console.WriteLine($"\n Methods: {methods.Count}");
|
||||
foreach (var method in methods)
|
||||
{
|
||||
Console.WriteLine($" - {method.Name}: {method.Annotations.Count} annotations");
|
||||
foreach (var annotation in method.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName}");
|
||||
}
|
||||
|
||||
// Check parameters
|
||||
foreach (var param in method.Parameters)
|
||||
{
|
||||
if (param.Annotations.Count > 0)
|
||||
{
|
||||
Console.WriteLine($" Parameter {param.Name}: {param.Annotations.Count} annotations");
|
||||
foreach (var annotation in param.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("✗ Parse failed!");
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
Console.WriteLine($" Error: {error.Message} at {error.Line}:{error.Column}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom visitor for code analysis
|
||||
|
||||
Reference in New Issue
Block a user