17 Commits

Author SHA1 Message Date
85fdcff103 Fixed annotation parsing in AstBuilder
pulled some hair out on this one
2025-07-23 07:29:16 -04:00
1e15e90d32 README and SPECIFICATION updated 2025-07-23 06:27:48 -04:00
aae6087f90 Hot Fix: nestedclasses
resolved empty nestedclasses
2025-07-23 06:10:17 -04:00
0955bb39e3 Version bump to 2.1.0 - Added nested types support 2025-07-23 05:44:24 -04:00
ccc7f1bc8c Merge pull request #1 from MarketAlly/Working/convenience
Nested Types support
2025-07-23 05:35:07 -04:00
6b1f3d7124 Update AstJsonSerializer.cs 2025-07-23 05:31:44 -04:00
5439aeb081 Resolved build errors
1. Fixed constructor calls in AstTransformer.cs by adding missing nestedTypes parameter
  2. Fixed constructor calls in AstJsonSerializer.cs by adding logic to deserialize nestedTypes
  3. Fixed constructor calls in AstBuilder.cs by adding empty nestedTypes lists and correct parameters
  4. Fixed test files by updating ClassDeclaration constructors with proper parameters
2025-07-23 05:24:18 -04:00
2cc1e3d283 new nested types 2025-07-23 05:10:45 -04:00
7708c479e8 tweaks 2025-07-23 05:01:42 -04:00
70c5858c94 Create API_SPECIFICATION.md 2025-07-23 03:16:47 -04:00
c881259f55 Updated readme 2025-07-23 01:21:16 -04:00
6800d0d7a9 Namespace change 2025-07-23 01:06:48 -04:00
0e716e083c Merge branch 'main' of https://github.com/MarketAlly/IronJava 2025-07-22 00:22:52 -04:00
aa3ac640cb Removed misc projects from NUGET 2025-07-22 00:16:28 -04:00
558616311c title updated 2025-07-22 00:11:41 -04:00
b4ebf4d363 merged notes 2025-07-22 00:11:05 -04:00
fc44f649c9 fix ci 2025-07-21 23:09:47 -04:00
38 changed files with 2041 additions and 187 deletions

View File

@@ -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
View File

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -5,6 +5,8 @@
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>MarketAlly.IronJava.Benchmarks</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>

View File

@@ -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)]

View File

@@ -1,6 +1,6 @@
using BenchmarkDotNet.Running;
namespace IronJava.Benchmarks
namespace MarketAlly.IronJava.Benchmarks
{
class Program
{

View File

@@ -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

View File

@@ -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>();
}
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,6 +1,6 @@
using System;
namespace IronJava.Core.AST
namespace MarketAlly.IronJava.Core.AST
{
/// <summary>
/// Java access modifiers and other modifiers as flags.

View File

@@ -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,

View File

@@ -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,

View File

@@ -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>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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.

View File

@@ -1,4 +1,4 @@
namespace IronJava.Core.AST
namespace MarketAlly.IronJava.Core.AST
{
/// <summary>
/// Represents a location in the source code.

View File

@@ -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
);

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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
{

View File

@@ -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");

View 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);
}
}
}

View File

@@ -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(

View File

@@ -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(

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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
{

View File

@@ -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
View 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}");
}
}
}
}

View File

@@ -5,6 +5,8 @@
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>MarketAlly.IronJava.Sample</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>

View File

@@ -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