diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..2544284
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,113 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# All files
+[*]
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+# Code files
+[*.{cs,csx,vb,vbx}]
+indent_style = space
+indent_size = 4
+
+# XML project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
+indent_size = 2
+
+# XML config files
+[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
+
+# JSON files
+[*.json]
+indent_size = 2
+
+# YAML files
+[*.{yml,yaml}]
+indent_size = 2
+
+# Markdown files
+[*.md]
+trim_trailing_whitespace = false
+
+# C# files
+[*.cs]
+
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+
+# Wrapping preferences
+csharp_preserve_single_line_statements = false
+csharp_preserve_single_line_blocks = true
+
+# Code style rules
+csharp_prefer_braces = true:warning
+csharp_prefer_simple_using_statement = true:suggestion
+
+# Expression preferences
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_prefer_switch_expression = true:suggestion
+csharp_style_prefer_pattern_matching = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:suggestion
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+
+# Code block preferences
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_namespace_declarations = file_scoped:suggestion
+
+# Expression-level preferences
+csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:warning
+
+# Naming conventions
+dotnet_naming_rule.interfaces_should_be_prefixed_with_i.severity = warning
+dotnet_naming_rule.interfaces_should_be_prefixed_with_i.symbols = interface_symbols
+dotnet_naming_rule.interfaces_should_be_prefixed_with_i.style = prefix_interface_with_i
+
+dotnet_naming_symbols.interface_symbols.applicable_kinds = interface
+dotnet_naming_symbols.interface_symbols.applicable_accessibilities = *
+
+dotnet_naming_style.prefix_interface_with_i.required_prefix = I
+dotnet_naming_style.prefix_interface_with_i.capitalization = pascal_case
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..e71cf57
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,132 @@
+name: CI
+
+on:
+ push:
+ branches: [ main, develop ]
+ pull_request:
+ branches: [ main ]
+ workflow_dispatch:
+
+env:
+ DOTNET_VERSION: '9.0.x'
+ DOTNET_NOLOGO: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+
+jobs:
+ build-and-test:
+ name: Build and Test
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ fail-fast: false
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --configuration Release --no-restore
+
+ - name: Test
+ run: dotnet test --configuration Release --no-build --verbosity normal --logger trx --results-directory TestResults
+
+ - name: Upload test results
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: test-results-${{ matrix.os }}
+ path: TestResults
+
+ code-coverage:
+ name: Code Coverage
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --configuration Debug --no-restore
+
+ - name: Test with coverage
+ run: dotnet test --configuration Debug --no-build --collect:"XPlat Code Coverage" --results-directory ./coverage
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v4
+ with:
+ directory: ./coverage
+ fail_ci_if_error: false
+ verbose: true
+
+ package:
+ name: Create NuGet Package
+ runs-on: ubuntu-latest
+ needs: [build-and-test]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --configuration Release --no-restore
+
+ - name: Pack
+ run: dotnet pack --configuration Release --no-build --output nupkgs
+
+ - name: Upload NuGet package
+ uses: actions/upload-artifact@v4
+ with:
+ name: nuget-packages
+ path: nupkgs/*.nupkg
+
+ publish:
+ name: Publish to NuGet
+ runs-on: ubuntu-latest
+ needs: [package]
+ if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+
+ steps:
+ - name: Download NuGet package
+ uses: actions/download-artifact@v4
+ with:
+ name: nuget-packages
+ path: nupkgs
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Publish to NuGet
+ run: |
+ 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
+ done
+ env:
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f4657d5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,250 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+
+# Visual Studio Code
+.vscode/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# macOS
+.DS_Store
+
+# Coverage
+coverage/
+*.coverage
+*.coveragexml
+
+# ANTLR generated files (already tracked in our case)
+# *.tokens
+# *.interp
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8122b66
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,157 @@
+# Contributing to IronJava
+
+Thank you for your interest in contributing to IronJava! This document provides guidelines and instructions for contributing.
+
+## Code of Conduct
+
+By participating in this project, you agree to abide by our Code of Conduct: be respectful, inclusive, and constructive in all interactions.
+
+## Getting Started
+
+1. Fork the repository
+2. Clone your fork: `git clone https://github.com/yourusername/IronJava.git`
+3. Create a feature branch: `git checkout -b feature/your-feature-name`
+4. Make your changes
+5. Run tests: `dotnet test`
+6. Commit your changes: `git commit -am 'Add new feature'`
+7. Push to your fork: `git push origin feature/your-feature-name`
+8. Create a Pull Request
+
+## Development Setup
+
+### Prerequisites
+
+- .NET 8.0 SDK or later
+- Visual Studio 2022, VS Code, or JetBrains Rider
+- Git
+
+### Building the Project
+
+```bash
+dotnet restore
+dotnet build
+```
+
+### Running Tests
+
+```bash
+dotnet test
+```
+
+## Project Structure
+
+```
+IronJava/
+├── IronJava.Core/ # Main library
+│ ├── AST/ # AST node definitions
+│ ├── Grammar/ # ANTLR grammar files
+│ ├── Parser/ # Parser implementation
+│ └── Serialization/ # JSON serialization
+├── IronJava.Tests/ # Unit tests
+├── IronJava.Benchmarks/ # Performance benchmarks
+└── IronJava.Samples/ # Example applications
+```
+
+## Coding Standards
+
+### C# Style Guide
+
+- Follow [Microsoft's C# Coding Conventions](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions)
+- Use meaningful variable and method names
+- Add XML documentation comments to public APIs
+- Keep methods focused and under 50 lines when possible
+
+### Commit Messages
+
+- Use present tense ("Add feature" not "Added feature")
+- Use imperative mood ("Move cursor to..." not "Moves cursor to...")
+- Limit first line to 72 characters
+- Reference issues and pull requests when applicable
+
+Example:
+```
+Add support for Java 17 switch expressions
+
+- Implement new AST nodes for switch expressions
+- Add visitor methods for traversal
+- Include comprehensive unit tests
+
+Fixes #123
+```
+
+## Testing
+
+### Unit Tests
+
+- Write tests for all new functionality
+- Maintain or improve code coverage
+- Use descriptive test names that explain what is being tested
+- Follow AAA pattern: Arrange, Act, Assert
+
+### Integration Tests
+
+- Test real-world Java code parsing
+- Verify cross-platform compatibility
+- Test error handling and edge cases
+
+## Pull Request Process
+
+1. **Before Submitting**
+ - Ensure all tests pass
+ - Update documentation if needed
+ - Add/update unit tests
+ - Run code formatting: `dotnet format`
+
+2. **PR Description**
+ - Clearly describe the changes
+ - Link related issues
+ - Include examples if applicable
+ - List any breaking changes
+
+3. **Review Process**
+ - Address reviewer feedback promptly
+ - Keep discussions focused and professional
+ - Be open to suggestions and alternative approaches
+
+## Adding New Features
+
+### AST Nodes
+
+When adding new AST node types:
+
+1. Define the node class in `AST/Nodes/`
+2. Implement visitor methods in `IJavaVisitor`
+3. Update visitor base classes
+4. Add serialization support
+5. Create unit tests
+
+### Grammar Changes
+
+If modifying the ANTLR grammar:
+
+1. Update the `.g4` files
+2. Regenerate parser/lexer code
+3. Update AST builder if needed
+4. Test with various Java code samples
+
+## Performance Considerations
+
+- Minimize allocations in hot paths
+- Use immutable designs where appropriate
+- Profile before optimizing
+- Add benchmarks for performance-critical code
+
+## Documentation
+
+- Update README.md for user-facing changes
+- Add XML documentation to public APIs
+- Include code examples in documentation
+- Update wiki for major features
+
+## Questions?
+
+- Open an issue for bugs or feature requests
+- Use discussions for questions and ideas
+- Join our community chat (if available)
+
+Thank you for contributing to IronJava!
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..c277e02
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,35 @@
+
+
+
+ latest
+ enable
+ enable
+ true
+
+ $(NoWarn);CS1591;CA1720;CA1304;CA1305;CA1311;CA1822;CA1852;CA1805;CA1002;CA1062;CA1860;CA2201;CA1859
+
+
+ true
+ strict
+
+
+ false
+
+
+ true
+ latest-recommended
+ false
+
+
+
+ portable
+ true
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
\ No newline at end of file
diff --git a/IronJava.Benchmarks/AstTraversalBenchmarks.cs b/IronJava.Benchmarks/AstTraversalBenchmarks.cs
new file mode 100644
index 0000000..f1aae0f
--- /dev/null
+++ b/IronJava.Benchmarks/AstTraversalBenchmarks.cs
@@ -0,0 +1,118 @@
+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;
+
+namespace IronJava.Benchmarks
+{
+ [MemoryDiagnoser]
+ public class AstTraversalBenchmarks
+ {
+ private CompilationUnit _ast = null!;
+ private CountingVisitor _visitor = null!;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ var javaCode = GenerateComplexJavaCode();
+ var result = JavaParser.Parse(javaCode);
+
+ if (!result.Success)
+ throw new Exception("Failed to parse test code");
+
+ _ast = result.Ast!;
+ _visitor = new CountingVisitor();
+ }
+
+ [Benchmark]
+ public void TraverseWithVisitor()
+ {
+ _visitor.Reset();
+ _ast.Accept(_visitor);
+ }
+
+ [Benchmark]
+ public void FindAllMethods()
+ {
+ var methods = _ast.FindAll().ToList();
+ }
+
+ [Benchmark]
+ public void QueryPublicMethods()
+ {
+ var methods = _ast.Query()
+ .WithModifier(Modifiers.Public)
+ .Execute()
+ .ToList();
+ }
+
+ [Benchmark]
+ public void FindMethodsWithLinq()
+ {
+ var methods = _ast.FindAll()
+ .Where(m => m.Modifiers.IsPublic() && !m.Modifiers.IsStatic())
+ .ToList();
+ }
+
+ [Benchmark]
+ public void ComplexQuery()
+ {
+ var results = _ast.FindAll()
+ .SelectMany(c => c.Members.OfType())
+ .Where(m => m.Parameters.Count > 2)
+ .Where(m => m.Modifiers.IsPublic())
+ .Select(m => new { m.Name, ParamCount = m.Parameters.Count })
+ .ToList();
+ }
+
+ private string GenerateComplexJavaCode()
+ {
+ var sb = new System.Text.StringBuilder();
+ sb.AppendLine("package benchmark.test;");
+ sb.AppendLine();
+
+ // Generate multiple classes
+ for (int c = 0; c < 10; c++)
+ {
+ sb.AppendLine($"public class TestClass{c} {{");
+
+ // Fields
+ for (int f = 0; f < 5; f++)
+ {
+ sb.AppendLine($" private String field{f};");
+ }
+
+ sb.AppendLine();
+
+ // Methods
+ for (int m = 0; m < 10; m++)
+ {
+ sb.AppendLine($" public void method{m}(String param1, int param2, Object param3) {{");
+ sb.AppendLine($" System.out.println(\"Method {m}\");");
+ sb.AppendLine($" }}");
+ sb.AppendLine();
+ }
+
+ sb.AppendLine("}");
+ sb.AppendLine();
+ }
+
+ return sb.ToString();
+ }
+
+ private class CountingVisitor : JavaVisitorBase
+ {
+ public int NodeCount { get; private set; }
+
+ public void Reset() => NodeCount = 0;
+
+ protected override void DefaultVisit(IronJava.Core.AST.JavaNode node)
+ {
+ NodeCount++;
+ base.DefaultVisit(node);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Benchmarks/IronJava.Benchmarks.csproj b/IronJava.Benchmarks/IronJava.Benchmarks.csproj
new file mode 100644
index 0000000..5420fdb
--- /dev/null
+++ b/IronJava.Benchmarks/IronJava.Benchmarks.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/IronJava.Benchmarks/ParsingBenchmarks.cs b/IronJava.Benchmarks/ParsingBenchmarks.cs
new file mode 100644
index 0000000..1d2b280
--- /dev/null
+++ b/IronJava.Benchmarks/ParsingBenchmarks.cs
@@ -0,0 +1,134 @@
+using BenchmarkDotNet.Attributes;
+using IronJava.Core;
+
+namespace IronJava.Benchmarks
+{
+ [MemoryDiagnoser]
+ [SimpleJob(warmupCount: 3, iterationCount: 5)]
+ public class ParsingBenchmarks
+ {
+ private string _simpleClass = null!;
+ private string _complexClass = null!;
+ private string _largeFile = null!;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+
+ _simpleClass = @"
+public class Simple {
+ private int value;
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+}";
+
+ _complexClass = @"
+package com.example.app;
+
+import java.util.*;
+import java.util.stream.*;
+import java.util.concurrent.*;
+
+@Service
+@Transactional
+public class ComplexService implements ServiceInterface {
+ private static final Logger LOG = LoggerFactory.getLogger(ComplexService.class);
+ private final Repository repository;
+ private final EventPublisher eventPublisher;
+
+ @Autowired
+ public ComplexService(Repository repository, EventPublisher eventPublisher) {
+ this.repository = repository;
+ this.eventPublisher = eventPublisher;
+ }
+
+ @Override
+ @Cacheable(value = ""entities"", key = ""#id"")
+ public Optional findById(Long id) {
+ LOG.debug(""Finding entity by id: {}"", id);
+ return repository.findById(id)
+ .map(entity -> {
+ eventPublisher.publish(new EntityAccessedEvent(entity));
+ return entity;
+ });
+ }
+
+ @Override
+ @Transactional(isolation = Isolation.READ_COMMITTED)
+ public CompletableFuture> findAllAsync() {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ return repository.findAll().stream()
+ .filter(Objects::nonNull)
+ .sorted(Comparator.comparing(Entity::getCreatedAt))
+ .collect(Collectors.toList());
+ } catch (Exception e) {
+ LOG.error(""Error finding entities"", e);
+ throw new ServiceException(""Failed to load entities"", e);
+ }
+ });
+ }
+
+ public record EntityAccessedEvent(Entity entity) implements DomainEvent {
+ @Override
+ public Instant occurredOn() {
+ return Instant.now();
+ }
+ }
+}";
+
+ // Generate a large file
+ var sb = new System.Text.StringBuilder();
+ sb.AppendLine("package com.example.generated;");
+ sb.AppendLine();
+ sb.AppendLine("public class LargeGeneratedClass {");
+
+ for (int i = 0; i < 100; i++)
+ {
+ sb.AppendLine($" private String field{i};");
+ sb.AppendLine($" ");
+ sb.AppendLine($" public String getField{i}() {{");
+ sb.AppendLine($" return field{i};");
+ sb.AppendLine($" }}");
+ sb.AppendLine($" ");
+ sb.AppendLine($" public void setField{i}(String field{i}) {{");
+ sb.AppendLine($" this.field{i} = field{i};");
+ sb.AppendLine($" }}");
+ sb.AppendLine();
+ }
+
+ sb.AppendLine("}");
+ _largeFile = sb.ToString();
+ }
+
+ [Benchmark]
+ public void ParseSimpleClass()
+ {
+ var result = JavaParser.Parse(_simpleClass);
+ if (!result.Success)
+ throw new Exception("Parse failed");
+ }
+
+ [Benchmark]
+ public void ParseComplexClass()
+ {
+ var result = JavaParser.Parse(_complexClass);
+ if (!result.Success)
+ throw new Exception("Parse failed");
+ }
+
+ [Benchmark]
+ public void ParseLargeFile()
+ {
+ var result = JavaParser.Parse(_largeFile);
+ if (!result.Success)
+ throw new Exception("Parse failed");
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Benchmarks/Program.cs b/IronJava.Benchmarks/Program.cs
new file mode 100644
index 0000000..e7dc18d
--- /dev/null
+++ b/IronJava.Benchmarks/Program.cs
@@ -0,0 +1,14 @@
+using BenchmarkDotNet.Running;
+
+namespace IronJava.Benchmarks
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ BenchmarkRunner.Run();
+ BenchmarkRunner.Run();
+ BenchmarkRunner.Run();
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Benchmarks/TransformationBenchmarks.cs b/IronJava.Benchmarks/TransformationBenchmarks.cs
new file mode 100644
index 0000000..bdac07c
--- /dev/null
+++ b/IronJava.Benchmarks/TransformationBenchmarks.cs
@@ -0,0 +1,99 @@
+using BenchmarkDotNet.Attributes;
+using IronJava.Core;
+using IronJava.Core.AST;
+using IronJava.Core.AST.Nodes;
+using IronJava.Core.AST.Transformation;
+using IronJava.Core.Serialization;
+
+namespace IronJava.Benchmarks
+{
+ [MemoryDiagnoser]
+ public class TransformationBenchmarks
+ {
+ private CompilationUnit _ast = null!;
+ private IdentifierRenamer _renamer = null!;
+ private ModifierTransformer _modifierTransformer = null!;
+ private TransformationBuilder _complexTransformer = null!;
+ private AstJsonSerializer _serializer = null!;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ var javaCode = @"
+package com.example;
+
+public class Service {
+ private Repository repository;
+ private Logger logger;
+
+ public Service(Repository repository) {
+ this.repository = repository;
+ this.logger = LoggerFactory.getLogger(Service.class);
+ }
+
+ public Entity findById(Long id) {
+ logger.debug(""Finding entity: "" + id);
+ return repository.findById(id);
+ }
+
+ public List findAll() {
+ logger.debug(""Finding all entities"");
+ return repository.findAll();
+ }
+
+ private void validateEntity(Entity entity) {
+ if (entity == null) {
+ throw new IllegalArgumentException(""Entity cannot be null"");
+ }
+ }
+}";
+
+ var result = JavaParser.Parse(javaCode);
+ if (!result.Success)
+ throw new Exception("Failed to parse test code");
+
+ _ast = result.Ast!;
+
+ _renamer = new IdentifierRenamer("repository", "repo");
+ _modifierTransformer = ModifierTransformer.AddModifier(Modifiers.Final);
+ _complexTransformer = new TransformationBuilder()
+ .AddModifier(Modifiers.Final)
+ .RenameIdentifier("repository", "repo")
+ .RenameIdentifier("logger", "log")
+ ;
+
+ _serializer = new AstJsonSerializer(indented: false);
+ }
+
+ [Benchmark]
+ public void SimpleRename()
+ {
+ var transformed = _ast.Accept(_renamer);
+ }
+
+ [Benchmark]
+ public void AddModifier()
+ {
+ var transformed = _ast.Accept(_modifierTransformer);
+ }
+
+ [Benchmark]
+ public void ComplexTransformation()
+ {
+ var transformed = _complexTransformer.Transform(_ast);
+ }
+
+ [Benchmark]
+ public void SerializeToJson()
+ {
+ var json = _serializer.Serialize(_ast);
+ }
+
+ [Benchmark]
+ public void TransformAndSerialize()
+ {
+ var transformed = _complexTransformer.Transform(_ast);
+ var json = _serializer.Serialize(transformed);
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Builders/AstBuilder.cs b/IronJava.Core/AST/Builders/AstBuilder.cs
new file mode 100644
index 0000000..9494c57
--- /dev/null
+++ b/IronJava.Core/AST/Builders/AstBuilder.cs
@@ -0,0 +1,3462 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Antlr4.Runtime;
+using Antlr4.Runtime.Misc;
+using Antlr4.Runtime.Tree;
+using IronJava.Core.AST.Nodes;
+using IronJava.Core.Grammar;
+
+namespace IronJava.Core.AST.Builders
+{
+ ///
+ /// Builds a typed AST from ANTLR parse tree.
+ ///
+ public class AstBuilder : Java9ParserBaseVisitor
+ {
+ private readonly ITokenStream _tokens;
+
+ public AstBuilder(ITokenStream tokens)
+ {
+ _tokens = tokens;
+ }
+
+ private SourceRange GetSourceRange(ParserRuleContext context)
+ {
+ var start = new SourceLocation(
+ context.Start.Line,
+ context.Start.Column,
+ context.Start.StartIndex,
+ context.Start.Text?.Length ?? 0
+ );
+
+ var stop = context.Stop ?? context.Start;
+ var end = new SourceLocation(
+ stop.Line,
+ stop.Column + (stop.Text?.Length ?? 0),
+ stop.StopIndex,
+ stop.Text?.Length ?? 0
+ );
+
+ return new SourceRange(start, end);
+ }
+
+ private SourceRange GetSourceRange(ITerminalNode node)
+ {
+ var token = node.Symbol;
+ var location = new SourceLocation(
+ token.Line,
+ token.Column,
+ token.StartIndex,
+ token.Text?.Length ?? 0
+ );
+ return new SourceRange(location, location);
+ }
+
+ private PrimitiveTypeKind ParsePrimitiveTypeKind(string typeName)
+ {
+ return typeName switch
+ {
+ "boolean" => PrimitiveTypeKind.Boolean,
+ "byte" => PrimitiveTypeKind.Byte,
+ "short" => PrimitiveTypeKind.Short,
+ "int" => PrimitiveTypeKind.Int,
+ "long" => PrimitiveTypeKind.Long,
+ "char" => PrimitiveTypeKind.Char,
+ "float" => PrimitiveTypeKind.Float,
+ "double" => PrimitiveTypeKind.Double,
+ "void" => PrimitiveTypeKind.Void,
+ _ => PrimitiveTypeKind.Int // Default fallback
+ };
+ }
+
+ public override JavaNode? VisitCompilationUnit(Java9Parser.CompilationUnitContext context)
+ {
+ var location = GetSourceRange(context);
+ PackageDeclaration? package = null;
+ var imports = new List();
+ var types = new List();
+
+ // Check if it's ordinary compilation or modular compilation
+ if (context.ordinaryCompilation() != null)
+ {
+ var ordinaryComp = context.ordinaryCompilation();
+
+ package = ordinaryComp.packageDeclaration() != null
+ ? Visit(ordinaryComp.packageDeclaration()) as PackageDeclaration
+ : null;
+
+ imports = ordinaryComp.importDeclaration()
+ .Select(i => Visit(i) as ImportDeclaration)
+ .Where(i => i != null)
+ .Cast()
+ .ToList();
+
+ types = ordinaryComp.typeDeclaration()
+ .Select(t => Visit(t) as TypeDeclaration)
+ .Where(t => t != null)
+ .Cast()
+ .ToList();
+ }
+ else if (context.modularCompilation() != null)
+ {
+ var modularComp = context.modularCompilation();
+
+ // Handle module declaration if needed
+ // For now, we'll just handle imports
+ imports = modularComp.importDeclaration()
+ .Select(i => Visit(i) as ImportDeclaration)
+ .Where(i => i != null)
+ .Cast()
+ .ToList();
+ }
+
+ return new CompilationUnit(location, package, imports, types);
+ }
+
+ public override JavaNode? VisitPackageDeclaration(Java9Parser.PackageDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var annotations = BuildAnnotations(context.packageModifier());
+ var packageName = context.packageName().GetText();
+
+ return new PackageDeclaration(location, packageName, annotations);
+ }
+
+ public override JavaNode? VisitImportDeclaration(Java9Parser.ImportDeclarationContext context)
+ {
+ if (context.singleTypeImportDeclaration() != null)
+ {
+ return VisitSingleTypeImportDeclaration(context.singleTypeImportDeclaration());
+ }
+ else if (context.typeImportOnDemandDeclaration() != null)
+ {
+ return VisitTypeImportOnDemandDeclaration(context.typeImportOnDemandDeclaration());
+ }
+ else if (context.singleStaticImportDeclaration() != null)
+ {
+ return VisitSingleStaticImportDeclaration(context.singleStaticImportDeclaration());
+ }
+ else if (context.staticImportOnDemandDeclaration() != null)
+ {
+ return VisitStaticImportOnDemandDeclaration(context.staticImportOnDemandDeclaration());
+ }
+
+ return null;
+ }
+
+ public override JavaNode? VisitSingleTypeImportDeclaration(Java9Parser.SingleTypeImportDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var typeName = context.typeName().GetText();
+ return new ImportDeclaration(location, typeName, false, false);
+ }
+
+ public override JavaNode? VisitTypeImportOnDemandDeclaration(Java9Parser.TypeImportOnDemandDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var packageOrTypeName = context.packageOrTypeName().GetText();
+ return new ImportDeclaration(location, packageOrTypeName, false, true);
+ }
+
+ public override JavaNode? VisitSingleStaticImportDeclaration(Java9Parser.SingleStaticImportDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var typeName = context.typeName().GetText() + "." + context.identifier().GetText();
+ return new ImportDeclaration(location, typeName, true, false);
+ }
+
+ public override JavaNode? VisitStaticImportOnDemandDeclaration(Java9Parser.StaticImportOnDemandDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var typeName = context.typeName().GetText();
+ return new ImportDeclaration(location, typeName, true, true);
+ }
+
+ public override JavaNode? VisitTypeDeclaration(Java9Parser.TypeDeclarationContext context)
+ {
+ if (context.classDeclaration() != null)
+ {
+ return Visit(context.classDeclaration());
+ }
+ else if (context.interfaceDeclaration() != null)
+ {
+ return Visit(context.interfaceDeclaration());
+ }
+
+ return null;
+ }
+
+ public override JavaNode? VisitNormalClassDeclaration(Java9Parser.NormalClassDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.classModifier());
+ var annotations = BuildAnnotations(context.classModifier());
+ var name = context.identifier().GetText();
+ 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 javaDoc = ExtractJavaDoc(context);
+
+ return new ClassDeclaration(
+ location, name, modifiers, annotations, typeParameters,
+ superClass, interfaces, members, javaDoc
+ );
+ }
+
+ public override JavaNode? VisitNormalInterfaceDeclaration(Java9Parser.NormalInterfaceDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.interfaceModifier());
+ var annotations = BuildAnnotations(context.interfaceModifier());
+ var name = context.identifier().GetText();
+ var typeParameters = BuildTypeParameters(context.typeParameters());
+ var extendedInterfaces = BuildExtendedInterfaces(context.extendsInterfaces());
+ var members = BuildInterfaceMembers(context.interfaceBody());
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new InterfaceDeclaration(
+ location, name, modifiers, annotations, typeParameters,
+ extendedInterfaces, members, javaDoc
+ );
+ }
+
+ public override JavaNode? VisitEnumDeclaration(Java9Parser.EnumDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.classModifier());
+ var annotations = BuildAnnotations(context.classModifier());
+ var name = context.identifier().GetText();
+ var interfaces = BuildInterfaces(context.superinterfaces());
+ var enumBody = context.enumBody();
+ var constants = BuildEnumConstants(enumBody.enumConstantList());
+ var members = BuildEnumMembers(enumBody.enumBodyDeclarations());
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new EnumDeclaration(
+ location, name, modifiers, annotations,
+ interfaces, constants, members, javaDoc
+ );
+ }
+
+ public override JavaNode? VisitAnnotationTypeDeclaration(Java9Parser.AnnotationTypeDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.interfaceModifier());
+ var annotations = BuildAnnotations(context.interfaceModifier());
+ var name = context.identifier().GetText();
+ var members = BuildAnnotationMembers(context.annotationTypeBody());
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new AnnotationDeclaration(
+ location, name, modifiers, annotations, members, javaDoc
+ );
+ }
+
+ // Helper methods for building AST components
+
+ private Modifiers BuildModifiers(IEnumerable? modifierContexts)
+ {
+ if (modifierContexts == null) return Modifiers.None;
+
+ var modifiers = Modifiers.None;
+ foreach (var modifier in modifierContexts)
+ {
+ var text = modifier.GetText();
+ modifiers |= text switch
+ {
+ "public" => Modifiers.Public,
+ "protected" => Modifiers.Protected,
+ "private" => Modifiers.Private,
+ "static" => Modifiers.Static,
+ "final" => Modifiers.Final,
+ "abstract" => Modifiers.Abstract,
+ "native" => Modifiers.Native,
+ "synchronized" => Modifiers.Synchronized,
+ "transient" => Modifiers.Transient,
+ "volatile" => Modifiers.Volatile,
+ "strictfp" => Modifiers.Strictfp,
+ "default" => Modifiers.Default,
+ "sealed" => Modifiers.Sealed,
+ "non-sealed" => Modifiers.NonSealed,
+ _ => Modifiers.None
+ };
+ }
+ return modifiers;
+ }
+
+ private List BuildAnnotations(IEnumerable? contexts)
+ {
+ if (contexts == null) return new List();
+
+ var annotations = new List();
+ foreach (var context in contexts)
+ {
+ if (context is Java9Parser.AnnotationContext annotationContext)
+ {
+ var annotation = BuildAnnotation(annotationContext);
+ if (annotation != null) annotations.Add(annotation);
+ }
+ }
+ return annotations;
+ }
+
+ private Annotation? BuildAnnotation(Java9Parser.AnnotationContext context)
+ {
+ var location = GetSourceRange(context);
+ TypeReference? type = null;
+ var arguments = new List();
+
+ // Annotations can be NormalAnnotation, MarkerAnnotation, or SingleElementAnnotation
+ if (context.normalAnnotation() != null)
+ {
+ var normalAnn = context.normalAnnotation();
+ type = BuildTypeReference(normalAnn.typeName());
+ if (type == null) return null;
+
+ if (normalAnn.elementValuePairList() != null)
+ {
+ foreach (var pair in normalAnn.elementValuePairList().elementValuePair())
+ {
+ var name = pair.identifier().GetText();
+ var value = BuildExpression(pair.elementValue());
+ if (value != null)
+ {
+ arguments.Add(new AnnotationValueArgument(
+ GetSourceRange(pair), name, value
+ ));
+ }
+ }
+ }
+ }
+ else if (context.markerAnnotation() != null)
+ {
+ var markerAnn = context.markerAnnotation();
+ type = BuildTypeReference(markerAnn.typeName());
+ if (type == null) return null;
+ // Marker annotations have no arguments
+ }
+ else if (context.singleElementAnnotation() != null)
+ {
+ var singleAnn = context.singleElementAnnotation();
+ type = BuildTypeReference(singleAnn.typeName());
+ if (type == null) return null;
+
+ if (singleAnn.elementValue() != null)
+ {
+ var value = BuildExpression(singleAnn.elementValue());
+ if (value != null)
+ {
+ arguments.Add(new AnnotationValueArgument(
+ location, "value", value
+ ));
+ }
+ }
+ }
+
+ return type != null ? new Annotation(location, type, arguments) : null;
+ }
+
+ private List BuildTypeParameters(Java9Parser.TypeParametersContext? context)
+ {
+ if (context == null) return new List();
+
+ return context.typeParameterList().typeParameter()
+ .Select(tp => BuildTypeParameter(tp))
+ .Where(tp => tp != null)
+ .Cast()
+ .ToList();
+ }
+
+ private TypeParameter? BuildTypeParameter(Java9Parser.TypeParameterContext context)
+ {
+ var location = GetSourceRange(context);
+ var name = context.identifier().GetText();
+ var bounds = new List();
+ var annotations = BuildAnnotations(context.typeParameterModifier());
+
+ if (context.typeBound() != null)
+ {
+ if (context.typeBound().typeVariable() != null)
+ {
+ var boundType = BuildTypeReference(context.typeBound().typeVariable());
+ if (boundType != null) bounds.Add(boundType);
+ }
+ else if (context.typeBound().classOrInterfaceType() != null)
+ {
+ var boundType = BuildTypeReference(context.typeBound().classOrInterfaceType());
+ if (boundType != null) bounds.Add(boundType);
+
+ foreach (var additionalBound in context.typeBound().additionalBound())
+ {
+ var additionalType = BuildTypeReference(additionalBound.interfaceType());
+ if (additionalType != null) bounds.Add(additionalType);
+ }
+ }
+ }
+
+ return new TypeParameter(location, name, bounds, annotations);
+ }
+
+ private TypeReference? BuildTypeReference(IParseTree? context)
+ {
+ if (context == null) return null;
+
+ return context switch
+ {
+ Java9Parser.PrimitiveTypeContext primitive => BuildPrimitiveType(primitive),
+ Java9Parser.ClassOrInterfaceTypeContext classOrInterface => BuildClassOrInterfaceType(classOrInterface),
+ 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),
+ _ => null
+ };
+ }
+
+ private PrimitiveType? BuildPrimitiveType(Java9Parser.PrimitiveTypeContext context)
+ {
+ var location = GetSourceRange(context);
+ var text = context.GetText();
+
+ var kind = text switch
+ {
+ "boolean" => PrimitiveTypeKind.Boolean,
+ "byte" => PrimitiveTypeKind.Byte,
+ "short" => PrimitiveTypeKind.Short,
+ "int" => PrimitiveTypeKind.Int,
+ "long" => PrimitiveTypeKind.Long,
+ "char" => PrimitiveTypeKind.Char,
+ "float" => PrimitiveTypeKind.Float,
+ "double" => PrimitiveTypeKind.Double,
+ _ => (PrimitiveTypeKind?)null
+ };
+
+ return kind.HasValue ? new PrimitiveType(location, kind.Value) : null;
+ }
+
+ private ClassOrInterfaceType? BuildClassOrInterfaceType(Java9Parser.ClassOrInterfaceTypeContext context)
+ {
+ ClassOrInterfaceType? current = null;
+
+ if (context.classType_lfno_classOrInterfaceType() != null)
+ {
+ current = BuildClassType_lfno(context.classType_lfno_classOrInterfaceType());
+ }
+ else if (context.interfaceType_lfno_classOrInterfaceType() != null)
+ {
+ current = BuildInterfaceType_lfno(context.interfaceType_lfno_classOrInterfaceType());
+ }
+
+ foreach (var additional in context.classType_lf_classOrInterfaceType())
+ {
+ var name = additional.identifier().GetText();
+ var typeArgs = BuildTypeArguments(additional.typeArguments());
+ var annotations = BuildAnnotations(additional.annotation());
+ var location = GetSourceRange(additional);
+
+ current = new ClassOrInterfaceType(location, name, current, typeArgs, annotations);
+ }
+
+ foreach (var additional in context.interfaceType_lf_classOrInterfaceType())
+ {
+ // InterfaceType_lf_classOrInterfaceType delegates to classType_lf_classOrInterfaceType
+ var classType = additional.classType_lf_classOrInterfaceType();
+ if (classType != null)
+ {
+ var name = classType.identifier().GetText();
+ var typeArgs = BuildTypeArguments(classType.typeArguments());
+ var annotations = BuildAnnotations(classType.annotation());
+ var location = GetSourceRange(additional);
+
+ current = new ClassOrInterfaceType(location, name, current, typeArgs, annotations);
+ }
+ }
+
+ return current;
+ }
+
+ private ClassOrInterfaceType? BuildClassType(Java9Parser.ClassTypeContext context)
+ {
+ var location = GetSourceRange(context);
+ var annotations = BuildAnnotations(context.annotation());
+
+ if (context.identifier() != null)
+ {
+ var name = context.identifier().GetText();
+ var typeArgs = BuildTypeArguments(context.typeArguments());
+ var scope = context.classOrInterfaceType() != null
+ ? BuildClassOrInterfaceType(context.classOrInterfaceType())
+ : null;
+
+ return new ClassOrInterfaceType(location, name, scope, typeArgs, annotations);
+ }
+
+ return null;
+ }
+
+ private ClassOrInterfaceType? BuildClassType_lfno(Java9Parser.ClassType_lfno_classOrInterfaceTypeContext context)
+ {
+ var location = GetSourceRange(context);
+ var name = context.identifier().GetText();
+ var typeArgs = BuildTypeArguments(context.typeArguments());
+ var annotations = BuildAnnotations(context.annotation());
+
+ return new ClassOrInterfaceType(location, name, null, typeArgs, annotations);
+ }
+
+ private ClassOrInterfaceType? BuildInterfaceType(Java9Parser.InterfaceTypeContext context)
+ {
+ return BuildClassType(context.classType());
+ }
+
+ private ClassOrInterfaceType? BuildInterfaceType_lfno(Java9Parser.InterfaceType_lfno_classOrInterfaceTypeContext context)
+ {
+ return BuildClassType_lfno(context.classType_lfno_classOrInterfaceType());
+ }
+
+ private ClassOrInterfaceType? BuildTypeName(Java9Parser.TypeNameContext context)
+ {
+ var location = GetSourceRange(context);
+ // TypeName has a recursive structure, just use GetText()
+ return new ClassOrInterfaceType(
+ location,
+ context.GetText(),
+ null,
+ new List(),
+ new List()
+ );
+ }
+
+ private ClassOrInterfaceType? BuildTypeVariable(Java9Parser.TypeVariableContext context)
+ {
+ var location = GetSourceRange(context);
+ var name = context.identifier().GetText();
+ var annotations = BuildAnnotations(context.annotation());
+
+ return new ClassOrInterfaceType(location, name, null, new List(), annotations);
+ }
+
+ private ArrayType? BuildArrayType(Java9Parser.ArrayTypeContext context)
+ {
+ TypeReference? elementType = null;
+ int dimensions = 0;
+
+ if (context.primitiveType() != null)
+ {
+ elementType = BuildPrimitiveType(context.primitiveType());
+ dimensions = context.dims().GetText().Length / 2; // Each dimension is "[]"
+ }
+ else if (context.classOrInterfaceType() != null)
+ {
+ elementType = BuildClassOrInterfaceType(context.classOrInterfaceType());
+ dimensions = context.dims().GetText().Length / 2;
+ }
+ else if (context.typeVariable() != null)
+ {
+ elementType = BuildTypeVariable(context.typeVariable());
+ dimensions = context.dims().GetText().Length / 2;
+ }
+
+ return elementType != null
+ ? new ArrayType(GetSourceRange(context), elementType, dimensions)
+ : null;
+ }
+
+ private List BuildTypeArguments(Java9Parser.TypeArgumentsContext? context)
+ {
+ if (context?.typeArgumentList() == null) return new List();
+
+ return context.typeArgumentList().typeArgument()
+ .Select(ta => BuildTypeArgument(ta))
+ .Where(ta => ta != null)
+ .Cast()
+ .ToList();
+ }
+
+ private TypeArgument? BuildTypeArgument(Java9Parser.TypeArgumentContext context)
+ {
+ if (context.referenceType() != null)
+ {
+ var type = BuildTypeReference(context.referenceType());
+ return type != null
+ ? new TypeArgumentType(GetSourceRange(context), type)
+ : null;
+ }
+ else if (context.wildcard() != null)
+ {
+ return BuildWildcard(context.wildcard());
+ }
+
+ return null;
+ }
+
+ private WildcardType? BuildWildcard(Java9Parser.WildcardContext context)
+ {
+ var location = GetSourceRange(context);
+ TypeReference? bound = null;
+ var boundKind = WildcardBoundKind.None;
+
+ if (context.wildcardBounds() != null)
+ {
+ var boundsContext = context.wildcardBounds();
+ if (boundsContext.referenceType() != null)
+ {
+ bound = BuildTypeReference(boundsContext.referenceType());
+ boundKind = boundsContext.GetChild(0).GetText() == "extends"
+ ? WildcardBoundKind.Extends
+ : WildcardBoundKind.Super;
+ }
+ }
+
+ return new WildcardType(location, bound, boundKind);
+ }
+
+ private List BuildInterfaces(Java9Parser.SuperinterfacesContext? context)
+ {
+ if (context?.interfaceTypeList() == null) return new List();
+
+ return context.interfaceTypeList().interfaceType()
+ .Select(i => BuildTypeReference(i))
+ .Where(i => i != null)
+ .Cast()
+ .ToList();
+ }
+
+ private List BuildExtendedInterfaces(Java9Parser.ExtendsInterfacesContext? context)
+ {
+ if (context?.interfaceTypeList() == null) return new List();
+
+ return context.interfaceTypeList().interfaceType()
+ .Select(i => BuildTypeReference(i))
+ .Where(i => i != null)
+ .Cast()
+ .ToList();
+ }
+
+ private List BuildClassMembers(Java9Parser.ClassBodyContext context)
+ {
+ var members = new List();
+
+ foreach (var declaration in context.classBodyDeclaration())
+ {
+ if (declaration.classMemberDeclaration() != null)
+ {
+ var member = BuildClassMember(declaration.classMemberDeclaration());
+ if (member != null) members.Add(member);
+ }
+ else if (declaration.instanceInitializer() != null)
+ {
+ var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
+ if (initializer != null) members.Add(initializer);
+ }
+ else if (declaration.staticInitializer() != null)
+ {
+ var initializer = BuildStaticInitializer(declaration.staticInitializer());
+ if (initializer != null) members.Add(initializer);
+ }
+ else if (declaration.constructorDeclaration() != null)
+ {
+ var constructor = BuildConstructor(declaration.constructorDeclaration());
+ if (constructor != null) members.Add(constructor);
+ }
+ }
+
+ return members;
+ }
+
+ private MemberDeclaration? BuildClassMember(Java9Parser.ClassMemberDeclarationContext context)
+ {
+ if (context.fieldDeclaration() != null)
+ {
+ return BuildFieldDeclaration(context.fieldDeclaration());
+ }
+ else if (context.methodDeclaration() != null)
+ {
+ 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;
+ }
+
+ return null;
+ }
+
+ private FieldDeclaration? BuildFieldDeclaration(Java9Parser.FieldDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.fieldModifier());
+ var annotations = BuildAnnotations(context.fieldModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var variables = context.variableDeclaratorList().variableDeclarator()
+ .Select(v => BuildVariableDeclarator(v))
+ .Where(v => v != null)
+ .Cast()
+ .ToList();
+
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new FieldDeclaration(location, modifiers, annotations, type, variables, javaDoc);
+ }
+
+ private VariableDeclarator? BuildVariableDeclarator(Java9Parser.VariableDeclaratorContext context)
+ {
+ var location = GetSourceRange(context);
+ var id = context.variableDeclaratorId();
+ var name = id.identifier().GetText();
+ var dimensions = id.dims()?.GetText().Length / 2 ?? 0;
+
+ Expression? initializer = null;
+ if (context.variableInitializer() != null)
+ {
+ initializer = BuildExpression(context.variableInitializer());
+ }
+
+ return new VariableDeclarator(location, name, dimensions, initializer);
+ }
+
+ private MethodDeclaration? BuildMethodDeclaration(Java9Parser.MethodDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.methodModifier());
+ var annotations = BuildAnnotations(context.methodModifier());
+ var header = context.methodHeader();
+
+ var typeParameters = BuildTypeParameters(header.typeParameters());
+ var returnType = BuildTypeReference(header.result());
+ var declarator = header.methodDeclarator();
+ var name = declarator.identifier().GetText();
+ var parameters = BuildParameters(declarator.formalParameterList());
+ var throws_ = BuildThrows(header.throws_());
+ var body = context.methodBody().block() != null
+ ? BuildBlock(context.methodBody().block())
+ : null;
+
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new MethodDeclaration(
+ location, name, modifiers, annotations, returnType,
+ typeParameters, parameters, throws_, body, javaDoc
+ );
+ }
+
+ private TypeReference? BuildTypeReference(Java9Parser.ResultContext? context)
+ {
+ if (context == null) return null;
+
+ if (context.unannType() != null)
+ {
+ return BuildTypeReference(context.unannType());
+ }
+ else if (context.GetText() == "void")
+ {
+ return new PrimitiveType(GetSourceRange(context), PrimitiveTypeKind.Void);
+ }
+
+ return null;
+ }
+
+ private TypeReference? BuildTypeReference(Java9Parser.UnannTypeContext? context)
+ {
+ if (context == null) return null;
+
+ if (context.unannPrimitiveType() != null)
+ {
+ return BuildPrimitiveType(context.unannPrimitiveType());
+ }
+ else if (context.unannReferenceType() != null)
+ {
+ return BuildTypeReference(context.unannReferenceType());
+ }
+
+ return null;
+ }
+
+ private PrimitiveType? BuildPrimitiveType(Java9Parser.UnannPrimitiveTypeContext context)
+ {
+ var location = GetSourceRange(context);
+ var text = context.GetText();
+
+ var kind = text switch
+ {
+ "boolean" => PrimitiveTypeKind.Boolean,
+ "byte" => PrimitiveTypeKind.Byte,
+ "short" => PrimitiveTypeKind.Short,
+ "int" => PrimitiveTypeKind.Int,
+ "long" => PrimitiveTypeKind.Long,
+ "char" => PrimitiveTypeKind.Char,
+ "float" => PrimitiveTypeKind.Float,
+ "double" => PrimitiveTypeKind.Double,
+ _ => (PrimitiveTypeKind?)null
+ };
+
+ return kind.HasValue ? new PrimitiveType(location, kind.Value) : null;
+ }
+
+ private TypeReference? BuildTypeReference(Java9Parser.UnannReferenceTypeContext? context)
+ {
+ if (context == null) return null;
+
+ if (context.unannClassOrInterfaceType() != null)
+ {
+ return BuildClassOrInterfaceType(context.unannClassOrInterfaceType());
+ }
+ else if (context.unannTypeVariable() != null)
+ {
+ return BuildTypeVariable(context.unannTypeVariable());
+ }
+ else if (context.unannArrayType() != null)
+ {
+ return BuildArrayType(context.unannArrayType());
+ }
+
+ return null;
+ }
+
+ private ClassOrInterfaceType? BuildClassOrInterfaceType(Java9Parser.UnannClassOrInterfaceTypeContext context)
+ {
+ ClassOrInterfaceType? current = null;
+
+ if (context.unannClassType_lfno_unannClassOrInterfaceType() != null)
+ {
+ var first = context.unannClassType_lfno_unannClassOrInterfaceType();
+ var name = first.identifier().GetText();
+ var typeArgs = BuildTypeArguments(first.typeArguments());
+ var location = GetSourceRange(first);
+
+ current = new ClassOrInterfaceType(location, name, null, typeArgs, new List());
+ }
+
+ foreach (var additional in context.unannClassType_lf_unannClassOrInterfaceType())
+ {
+ var name = additional.identifier().GetText();
+ var typeArgs = BuildTypeArguments(additional.typeArguments());
+ var location = GetSourceRange(additional);
+
+ current = new ClassOrInterfaceType(location, name, current, typeArgs, new List());
+ }
+
+ return current;
+ }
+
+ private ClassOrInterfaceType? BuildTypeVariable(Java9Parser.UnannTypeVariableContext context)
+ {
+ var location = GetSourceRange(context);
+ var name = context.identifier().GetText();
+
+ return new ClassOrInterfaceType(location, name, null, new List(), new List());
+ }
+
+ private ArrayType? BuildArrayType(Java9Parser.UnannArrayTypeContext context)
+ {
+ TypeReference? elementType = null;
+ int dimensions = 0;
+
+ if (context.unannPrimitiveType() != null)
+ {
+ elementType = BuildPrimitiveType(context.unannPrimitiveType());
+ dimensions = context.dims().GetText().Length / 2;
+ }
+ else if (context.unannClassOrInterfaceType() != null)
+ {
+ elementType = BuildClassOrInterfaceType(context.unannClassOrInterfaceType());
+ dimensions = context.dims().GetText().Length / 2;
+ }
+ else if (context.unannTypeVariable() != null)
+ {
+ elementType = BuildTypeVariable(context.unannTypeVariable());
+ dimensions = context.dims().GetText().Length / 2;
+ }
+
+ return elementType != null
+ ? new ArrayType(GetSourceRange(context), elementType, dimensions)
+ : null;
+ }
+
+ private List BuildParameters(Java9Parser.FormalParameterListContext? context)
+ {
+ if (context == null) return new List();
+
+ var parameters = new List();
+
+ if (context.formalParameters() != null)
+ {
+ foreach (var param in context.formalParameters().formalParameter())
+ {
+ var parameter = BuildParameter(param);
+ if (parameter != null) parameters.Add(parameter);
+ }
+
+ if (context.formalParameters().receiverParameter() != null)
+ {
+ // Skip receiver parameter for now
+ }
+ }
+
+ if (context.lastFormalParameter() != null)
+ {
+ var parameter = BuildLastParameter(context.lastFormalParameter());
+ if (parameter != null) parameters.Add(parameter);
+ }
+
+ return parameters;
+ }
+
+ private Parameter? BuildParameter(Java9Parser.FormalParameterContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.variableModifier());
+ var annotations = BuildAnnotations(context.variableModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var declaratorId = context.variableDeclaratorId();
+ var name = declaratorId.identifier().GetText();
+ var isFinal = modifiers.HasFlag(Modifiers.Final);
+
+ // Handle array dimensions on parameter name
+ if (declaratorId.dims() != null)
+ {
+ var dimensions = declaratorId.dims().GetText().Length / 2;
+ type = new ArrayType(location, type, dimensions);
+ }
+
+ return new Parameter(location, type, name, false, isFinal, annotations);
+ }
+
+ private Parameter? BuildLastParameter(Java9Parser.LastFormalParameterContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.variableModifier());
+ var annotations = BuildAnnotations(context.variableModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var declaratorId = context.variableDeclaratorId();
+ var name = declaratorId.identifier().GetText();
+ var isFinal = modifiers.HasFlag(Modifiers.Final);
+ var isVarArgs = context.GetChild(context.ChildCount - 2)?.GetText() == "...";
+
+ return new Parameter(location, type, name, isVarArgs, isFinal, annotations);
+ }
+
+ private List BuildThrows(Java9Parser.Throws_Context? context)
+ {
+ if (context?.exceptionTypeList() == null) return new List();
+
+ return context.exceptionTypeList().exceptionType()
+ .Select(e => BuildTypeReference(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList();
+ }
+
+ private TypeReference? BuildTypeReference(Java9Parser.ExceptionTypeContext context)
+ {
+ if (context.classType() != null)
+ {
+ return BuildClassType(context.classType());
+ }
+ else if (context.typeVariable() != null)
+ {
+ return BuildTypeVariable(context.typeVariable());
+ }
+
+ return null;
+ }
+
+ private MethodDeclaration? BuildConstructor(Java9Parser.ConstructorDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.constructorModifier());
+ var annotations = BuildAnnotations(context.constructorModifier());
+ var declarator = context.constructorDeclarator();
+ var typeParameters = BuildTypeParameters(declarator.typeParameters());
+ var name = declarator.simpleTypeName().identifier().GetText();
+ var parameters = BuildParameters(declarator.formalParameterList());
+ var throws_ = BuildThrows(context.throws_());
+ var body = context.constructorBody().blockStatements() != null
+ ? BuildBlockFromStatements(context.constructorBody().blockStatements())
+ : new BlockStatement(GetSourceRange(context.constructorBody()), new List());
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new MethodDeclaration(
+ location, name, modifiers, annotations, null,
+ typeParameters, parameters, throws_, body, javaDoc, true
+ );
+ }
+
+ private InitializerBlock? BuildInstanceInitializer(Java9Parser.InstanceInitializerContext context)
+ {
+ var location = GetSourceRange(context);
+ var body = BuildBlock(context.block());
+ return body != null ? new InitializerBlock(location, body, false) : null;
+ }
+
+ private InitializerBlock? BuildStaticInitializer(Java9Parser.StaticInitializerContext context)
+ {
+ var location = GetSourceRange(context);
+ var body = BuildBlock(context.block());
+ return body != null ? new InitializerBlock(location, body, true) : null;
+ }
+
+ private List BuildInterfaceMembers(Java9Parser.InterfaceBodyContext context)
+ {
+ var members = new List();
+
+ foreach (var declaration in context.interfaceMemberDeclaration())
+ {
+ if (declaration.constantDeclaration() != null)
+ {
+ var constant = BuildConstantDeclaration(declaration.constantDeclaration());
+ if (constant != null) members.Add(constant);
+ }
+ else if (declaration.interfaceMethodDeclaration() != null)
+ {
+ var method = BuildInterfaceMethodDeclaration(declaration.interfaceMethodDeclaration());
+ if (method != null) members.Add(method);
+ }
+ else if (declaration.classDeclaration() != null)
+ {
+ var classDecl = Visit(declaration.classDeclaration()) as MemberDeclaration;
+ if (classDecl != null) members.Add(classDecl);
+ }
+ else if (declaration.interfaceDeclaration() != null)
+ {
+ var interfaceDecl = Visit(declaration.interfaceDeclaration()) as MemberDeclaration;
+ if (interfaceDecl != null) members.Add(interfaceDecl);
+ }
+ }
+
+ return members;
+ }
+
+ private FieldDeclaration? BuildConstantDeclaration(Java9Parser.ConstantDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.constantModifier()) | Modifiers.Public | Modifiers.Static | Modifiers.Final;
+ var annotations = BuildAnnotations(context.constantModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var variables = context.variableDeclaratorList().variableDeclarator()
+ .Select(v => BuildVariableDeclarator(v))
+ .Where(v => v != null)
+ .Cast()
+ .ToList();
+
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new FieldDeclaration(location, modifiers, annotations, type, variables, javaDoc);
+ }
+
+ private MethodDeclaration? BuildInterfaceMethodDeclaration(Java9Parser.InterfaceMethodDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.interfaceMethodModifier());
+ var annotations = BuildAnnotations(context.interfaceMethodModifier());
+ var header = context.methodHeader();
+
+ var typeParameters = BuildTypeParameters(header.typeParameters());
+ var returnType = BuildTypeReference(header.result());
+ var declarator = header.methodDeclarator();
+ var name = declarator.identifier().GetText();
+ var parameters = BuildParameters(declarator.formalParameterList());
+ var throws_ = BuildThrows(header.throws_());
+ var body = context.methodBody().block() != null
+ ? BuildBlock(context.methodBody().block())
+ : null;
+
+ var javaDoc = ExtractJavaDoc(context);
+
+ return new MethodDeclaration(
+ location, name, modifiers, annotations, returnType,
+ typeParameters, parameters, throws_, body, javaDoc
+ );
+ }
+
+ private List BuildEnumConstants(Java9Parser.EnumConstantListContext? context)
+ {
+ if (context == null) return new List();
+
+ return context.enumConstant()
+ .Select(ec => BuildEnumConstant(ec))
+ .Where(ec => ec != null)
+ .Cast()
+ .ToList();
+ }
+
+ private EnumConstant? BuildEnumConstant(Java9Parser.EnumConstantContext context)
+ {
+ var location = GetSourceRange(context);
+ var name = context.identifier().GetText();
+ var annotations = BuildAnnotations(context.enumConstantModifier());
+ var arguments = new List();
+
+ if (context.argumentList() != null)
+ {
+ arguments = context.argumentList().expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList();
+ }
+
+ ClassDeclaration? body = null;
+ if (context.classBody() != null)
+ {
+ // Build anonymous class body
+ var members = BuildClassMembers(context.classBody());
+ body = new ClassDeclaration(
+ GetSourceRange(context.classBody()),
+ "", // Anonymous
+ Modifiers.None,
+ new List(),
+ new List(),
+ null,
+ new List(),
+ members,
+ null
+ );
+ }
+
+ return new EnumConstant(location, name, annotations, arguments, body);
+ }
+
+ private List BuildEnumMembers(Java9Parser.EnumBodyDeclarationsContext? context)
+ {
+ if (context == null) return new List();
+
+ return BuildClassMembers(context);
+ }
+
+ private List BuildClassMembers(Java9Parser.EnumBodyDeclarationsContext context)
+ {
+ var members = new List();
+
+ foreach (var declaration in context.classBodyDeclaration())
+ {
+ if (declaration.classMemberDeclaration() != null)
+ {
+ var member = BuildClassMember(declaration.classMemberDeclaration());
+ if (member != null) members.Add(member);
+ }
+ else if (declaration.instanceInitializer() != null)
+ {
+ var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
+ if (initializer != null) members.Add(initializer);
+ }
+ else if (declaration.staticInitializer() != null)
+ {
+ var initializer = BuildStaticInitializer(declaration.staticInitializer());
+ if (initializer != null) members.Add(initializer);
+ }
+ else if (declaration.constructorDeclaration() != null)
+ {
+ var constructor = BuildConstructor(declaration.constructorDeclaration());
+ if (constructor != null) members.Add(constructor);
+ }
+ }
+
+ return members;
+ }
+
+ private List BuildAnnotationMembers(Java9Parser.AnnotationTypeBodyContext context)
+ {
+ var members = new List();
+
+ foreach (var declaration in context.annotationTypeMemberDeclaration())
+ {
+ if (declaration.annotationTypeElementDeclaration() != null)
+ {
+ var member = BuildAnnotationElement(declaration.annotationTypeElementDeclaration());
+ if (member != null) members.Add(member);
+ }
+ }
+
+ return members;
+ }
+
+ private AnnotationMember? BuildAnnotationElement(Java9Parser.AnnotationTypeElementDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var name = context.identifier().GetText();
+ Expression? defaultValue = null;
+
+ if (context.defaultValue() != null)
+ {
+ defaultValue = BuildExpression(context.defaultValue().elementValue());
+ }
+
+ return new AnnotationMember(location, name, type, defaultValue);
+ }
+
+ // Expression building methods
+
+ private Expression? BuildExpression(IParseTree? context)
+ {
+ if (context == null) return null;
+
+ return context switch
+ {
+ Java9Parser.ExpressionContext expr => BuildExpression(expr),
+ Java9Parser.LiteralContext literal => BuildLiteral(literal),
+ Java9Parser.PrimaryContext primary => BuildPrimary(primary),
+ Java9Parser.ElementValueContext elementValue => BuildElementValue(elementValue),
+ Java9Parser.VariableInitializerContext varInit => BuildVariableInitializer(varInit),
+ Java9Parser.ArrayInitializerContext arrayInit => BuildArrayInitializer(arrayInit),
+ _ => null
+ };
+ }
+
+ private Expression? BuildExpression(Java9Parser.ExpressionContext context)
+ {
+ if (context.lambdaExpression() != null)
+ {
+ return BuildLambdaExpression(context.lambdaExpression());
+ }
+ else if (context.assignmentExpression() != null)
+ {
+ return BuildAssignmentExpression(context.assignmentExpression());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildAssignmentExpression(Java9Parser.AssignmentExpressionContext context)
+ {
+ if (context.conditionalExpression() != null)
+ {
+ return BuildConditionalExpression(context.conditionalExpression());
+ }
+ else if (context.assignment() != null)
+ {
+ return BuildAssignment(context.assignment());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildAssignment(Java9Parser.AssignmentContext context)
+ {
+ var location = GetSourceRange(context);
+ var left = BuildExpression(context.leftHandSide());
+ var right = BuildExpression(context.expression());
+
+ if (left == null || right == null) return null;
+
+ var operatorText = context.assignmentOperator().GetText();
+ var @operator = operatorText switch
+ {
+ "=" => BinaryOperator.Assign,
+ "+=" => BinaryOperator.AddAssign,
+ "-=" => BinaryOperator.SubtractAssign,
+ "*=" => BinaryOperator.MultiplyAssign,
+ "/=" => BinaryOperator.DivideAssign,
+ "%=" => BinaryOperator.ModuloAssign,
+ "&=" => BinaryOperator.BitwiseAndAssign,
+ "|=" => BinaryOperator.BitwiseOrAssign,
+ "^=" => BinaryOperator.BitwiseXorAssign,
+ "<<=" => BinaryOperator.LeftShiftAssign,
+ ">>=" => BinaryOperator.RightShiftAssign,
+ ">>>=" => BinaryOperator.UnsignedRightShiftAssign,
+ _ => BinaryOperator.Assign
+ };
+
+ return new BinaryExpression(location, left, @operator, right);
+ }
+
+ private Expression? BuildExpression(Java9Parser.LeftHandSideContext context)
+ {
+ if (context.expressionName() != null)
+ {
+ return BuildExpressionName(context.expressionName());
+ }
+ else if (context.fieldAccess() != null)
+ {
+ return BuildFieldAccess(context.fieldAccess());
+ }
+ else if (context.arrayAccess() != null)
+ {
+ return BuildArrayAccess(context.arrayAccess());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildConditionalExpression(Java9Parser.ConditionalExpressionContext context)
+ {
+ if (context.conditionalOrExpression() != null &&
+ context.expression() == null)
+ {
+ return BuildConditionalOrExpression(context.conditionalOrExpression());
+ }
+ else if (context.conditionalOrExpression() != null &&
+ context.expression() != null &&
+ context.conditionalExpression() != null)
+ {
+ var location = GetSourceRange(context);
+ var condition = BuildConditionalOrExpression(context.conditionalOrExpression());
+ var thenExpr = BuildExpression(context.expression());
+ var elseExpr = BuildConditionalExpression(context.conditionalExpression());
+
+ if (condition != null && thenExpr != null && elseExpr != null)
+ {
+ return new ConditionalExpression(location, condition, thenExpr, elseExpr);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildConditionalOrExpression(Java9Parser.ConditionalOrExpressionContext context)
+ {
+ // Handle left-recursive grammar
+ if (context.conditionalAndExpression() != null && context.conditionalOrExpression() == null)
+ {
+ // Simple case - just one conditional AND expression
+ return BuildConditionalAndExpression(context.conditionalAndExpression());
+ }
+ else if (context.conditionalOrExpression() != null && context.conditionalAndExpression() != null)
+ {
+ // Binary OR expression
+ var left = BuildConditionalOrExpression(context.conditionalOrExpression());
+ var right = BuildConditionalAndExpression(context.conditionalAndExpression());
+
+ if (left != null && right != null)
+ {
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, BinaryOperator.LogicalOr, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildConditionalAndExpression(Java9Parser.ConditionalAndExpressionContext context)
+ {
+ // Handle left-recursive grammar
+ if (context.inclusiveOrExpression() != null && context.conditionalAndExpression() == null)
+ {
+ // Simple case - just one inclusive OR expression
+ return BuildInclusiveOrExpression(context.inclusiveOrExpression());
+ }
+ else if (context.conditionalAndExpression() != null && context.inclusiveOrExpression() != null)
+ {
+ // Binary AND expression
+ var left = BuildConditionalAndExpression(context.conditionalAndExpression());
+ var right = BuildInclusiveOrExpression(context.inclusiveOrExpression());
+
+ if (left != null && right != null)
+ {
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, BinaryOperator.LogicalAnd, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildInclusiveOrExpression(Java9Parser.InclusiveOrExpressionContext context)
+ {
+ // Handle left-recursive grammar
+ if (context.exclusiveOrExpression() != null && context.inclusiveOrExpression() == null)
+ {
+ // Simple case - just one exclusive OR expression
+ return BuildExclusiveOrExpression(context.exclusiveOrExpression());
+ }
+ else if (context.inclusiveOrExpression() != null && context.exclusiveOrExpression() != null)
+ {
+ // Binary OR expression
+ var left = BuildInclusiveOrExpression(context.inclusiveOrExpression());
+ var right = BuildExclusiveOrExpression(context.exclusiveOrExpression());
+
+ if (left != null && right != null)
+ {
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, BinaryOperator.BitwiseOr, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildExclusiveOrExpression(Java9Parser.ExclusiveOrExpressionContext context)
+ {
+ // Handle left-recursive grammar
+ if (context.andExpression() != null && context.exclusiveOrExpression() == null)
+ {
+ // Simple case - just one AND expression
+ return BuildAndExpression(context.andExpression());
+ }
+ else if (context.exclusiveOrExpression() != null && context.andExpression() != null)
+ {
+ // Binary XOR expression
+ var left = BuildExclusiveOrExpression(context.exclusiveOrExpression());
+ var right = BuildAndExpression(context.andExpression());
+
+ if (left != null && right != null)
+ {
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, BinaryOperator.BitwiseXor, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildAndExpression(Java9Parser.AndExpressionContext context)
+ {
+ // Handle left-recursive grammar
+ if (context.equalityExpression() != null && context.andExpression() == null)
+ {
+ // Simple case - just one equality expression
+ return BuildEqualityExpression(context.equalityExpression());
+ }
+ else if (context.andExpression() != null && context.equalityExpression() != null)
+ {
+ // Binary AND expression
+ var left = BuildAndExpression(context.andExpression());
+ var right = BuildEqualityExpression(context.equalityExpression());
+
+ if (left != null && right != null)
+ {
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, BinaryOperator.BitwiseAnd, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildEqualityExpression(Java9Parser.EqualityExpressionContext context)
+ {
+ // Handle left-recursive grammar
+ if (context.relationalExpression() != null && context.equalityExpression() == null)
+ {
+ // Simple case - just one relational expression
+ return BuildRelationalExpression(context.relationalExpression());
+ }
+ else if (context.equalityExpression() != null && context.relationalExpression() != null)
+ {
+ // Binary equality expression
+ var left = BuildEqualityExpression(context.equalityExpression());
+ var right = BuildRelationalExpression(context.relationalExpression());
+
+ if (left != null && right != null)
+ {
+ var @operator = context.EQUAL() != null ? BinaryOperator.Equals : BinaryOperator.NotEquals;
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, @operator, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildRelationalExpression(Java9Parser.RelationalExpressionContext context)
+ {
+ // Handle instanceof expression
+ if (context.referenceType() != null && context.shiftExpression() != null)
+ {
+ var location = GetSourceRange(context);
+ var expr = BuildShiftExpression(context.shiftExpression());
+ var type = BuildTypeReference(context.referenceType());
+ if (expr != null && type != null)
+ {
+ return new InstanceOfExpression(location, expr, type);
+ }
+ }
+ // Handle left-recursive grammar for relational expressions
+ else if (context.shiftExpression() != null && context.relationalExpression() == null)
+ {
+ // Simple case - just one shift expression
+ return BuildShiftExpression(context.shiftExpression());
+ }
+ else if (context.relationalExpression() != null && context.shiftExpression() != null)
+ {
+ // Binary relational expression
+ var left = BuildRelationalExpression(context.relationalExpression());
+ var right = BuildShiftExpression(context.shiftExpression());
+
+ if (left != null && right != null)
+ {
+ BinaryOperator @operator;
+ if (context.LT() != null) @operator = BinaryOperator.LessThan;
+ else if (context.GT() != null) @operator = BinaryOperator.GreaterThan;
+ else if (context.LE() != null) @operator = BinaryOperator.LessThanOrEqual;
+ else if (context.GE() != null) @operator = BinaryOperator.GreaterThanOrEqual;
+ else @operator = BinaryOperator.LessThan;
+
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, @operator, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildShiftExpression(Java9Parser.ShiftExpressionContext context)
+ {
+ // Handle left-recursive grammar for shift expressions
+ if (context.additiveExpression() != null && context.shiftExpression() == null)
+ {
+ // Simple case - just one additive expression
+ return BuildAdditiveExpression(context.additiveExpression());
+ }
+ else if (context.shiftExpression() != null && context.additiveExpression() != null)
+ {
+ // Binary shift expression
+ var left = BuildShiftExpression(context.shiftExpression());
+ var right = BuildAdditiveExpression(context.additiveExpression());
+
+ if (left != null && right != null)
+ {
+ // Check the operator between the operands
+ BinaryOperator @operator;
+ var operatorText = "";
+ var gtCount = 0;
+ var ltCount = 0;
+
+ // Count consecutive < or > operators
+ for (int i = 0; i < context.ChildCount; i++)
+ {
+ var child = context.GetChild(i);
+ var text = child.GetText();
+ if (text == "<")
+ {
+ ltCount++;
+ if (ltCount == 2)
+ {
+ operatorText = "<<";
+ break;
+ }
+ }
+ else if (text == ">")
+ {
+ gtCount++;
+ if (gtCount == 3)
+ {
+ operatorText = ">>>";
+ break;
+ }
+ else if (gtCount == 2 && i + 1 < context.ChildCount && context.GetChild(i + 1).GetText() != ">")
+ {
+ operatorText = ">>";
+ break;
+ }
+ }
+ else if (ltCount > 0 || gtCount > 0)
+ {
+ // Reset if we hit a non-operator
+ break;
+ }
+ }
+
+ @operator = operatorText switch
+ {
+ "<<" => BinaryOperator.LeftShift,
+ ">>" => BinaryOperator.RightShift,
+ ">>>" => BinaryOperator.UnsignedRightShift,
+ _ => BinaryOperator.LeftShift
+ };
+
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, @operator, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildAdditiveExpression(Java9Parser.AdditiveExpressionContext context)
+ {
+ // Handle left-recursive grammar for additive expressions
+ if (context.multiplicativeExpression() != null && context.additiveExpression() == null)
+ {
+ // Simple case - just one multiplicative expression
+ return BuildMultiplicativeExpression(context.multiplicativeExpression());
+ }
+ else if (context.additiveExpression() != null && context.multiplicativeExpression() != null)
+ {
+ // Binary additive expression
+ var left = BuildAdditiveExpression(context.additiveExpression());
+ var right = BuildMultiplicativeExpression(context.multiplicativeExpression());
+
+ if (left != null && right != null)
+ {
+ // Check the operator between the operands
+ var operatorText = "";
+ for (int i = 0; i < context.ChildCount; i++)
+ {
+ var child = context.GetChild(i);
+ if (child.GetText() == "+" || child.GetText() == "-")
+ {
+ operatorText = child.GetText();
+ break;
+ }
+ }
+
+ var @operator = operatorText == "+" ? BinaryOperator.Add : BinaryOperator.Subtract;
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, @operator, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildMultiplicativeExpression(Java9Parser.MultiplicativeExpressionContext context)
+ {
+ // Handle left-recursive grammar for multiplicative expressions
+ if (context.unaryExpression() != null && context.multiplicativeExpression() == null)
+ {
+ // Simple case - just one unary expression
+ return BuildUnaryExpression(context.unaryExpression());
+ }
+ else if (context.multiplicativeExpression() != null && context.unaryExpression() != null)
+ {
+ // Binary multiplicative expression
+ var left = BuildMultiplicativeExpression(context.multiplicativeExpression());
+ var right = BuildUnaryExpression(context.unaryExpression());
+
+ if (left != null && right != null)
+ {
+ BinaryOperator @operator;
+ // Check the operator between the operands
+ var operatorText = "";
+ for (int i = 0; i < context.ChildCount; i++)
+ {
+ var child = context.GetChild(i);
+ if (child.GetText() == "*" || child.GetText() == "/" || child.GetText() == "%")
+ {
+ operatorText = child.GetText();
+ break;
+ }
+ }
+
+ @operator = operatorText switch
+ {
+ "*" => BinaryOperator.Multiply,
+ "/" => BinaryOperator.Divide,
+ "%" => BinaryOperator.Modulo,
+ _ => BinaryOperator.Multiply
+ };
+
+ var location = new SourceRange(left.Location.Start, right.Location.End);
+ return new BinaryExpression(location, left, @operator, right);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildUnaryExpression(Java9Parser.UnaryExpressionContext context)
+ {
+ if (context.preIncrementExpression() != null)
+ {
+ return BuildPreIncrementExpression(context.preIncrementExpression());
+ }
+ else if (context.preDecrementExpression() != null)
+ {
+ return BuildPreDecrementExpression(context.preDecrementExpression());
+ }
+ else if (context.unaryExpressionNotPlusMinus() != null)
+ {
+ return BuildUnaryExpressionNotPlusMinus(context.unaryExpressionNotPlusMinus());
+ }
+ else if (context.GetChild(0).GetText() == "+" && context.unaryExpression() != null)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildUnaryExpression(context.unaryExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.Plus, operand)
+ : null;
+ }
+ else if (context.GetChild(0).GetText() == "-" && context.unaryExpression() != null)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildUnaryExpression(context.unaryExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.Minus, operand)
+ : null;
+ }
+
+ return null;
+ }
+
+ private Expression? BuildPreIncrementExpression(Java9Parser.PreIncrementExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildUnaryExpression(context.unaryExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.PreIncrement, operand)
+ : null;
+ }
+
+ private Expression? BuildPreDecrementExpression(Java9Parser.PreDecrementExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildUnaryExpression(context.unaryExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.PreDecrement, operand)
+ : null;
+ }
+
+ private Expression? BuildUnaryExpressionNotPlusMinus(Java9Parser.UnaryExpressionNotPlusMinusContext context)
+ {
+ if (context.postfixExpression() != null)
+ {
+ return BuildPostfixExpression(context.postfixExpression());
+ }
+ else if (context.GetChild(0).GetText() == "~" && context.unaryExpression() != null)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildUnaryExpression(context.unaryExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.BitwiseNot, operand)
+ : null;
+ }
+ else if (context.GetChild(0).GetText() == "!" && context.unaryExpression() != null)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildUnaryExpression(context.unaryExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.LogicalNot, operand)
+ : null;
+ }
+ else if (context.castExpression() != null)
+ {
+ return BuildCastExpression(context.castExpression());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildPostfixExpression(Java9Parser.PostfixExpressionContext context)
+ {
+ Expression? expr = null;
+
+ if (context.primary() != null)
+ {
+ expr = BuildPrimary(context.primary());
+ }
+ else if (context.expressionName() != null)
+ {
+ expr = BuildExpressionName(context.expressionName());
+ }
+
+ if (expr == null) return null;
+
+ // Handle postfix operators
+ foreach (var child in context.children.Skip(1))
+ {
+ if (child.GetText() == "++")
+ {
+ var location = new SourceRange(expr.Location.Start, GetSourceRange(context).End);
+ expr = new UnaryExpression(location, UnaryOperator.PostIncrement, expr, false);
+ }
+ else if (child.GetText() == "--")
+ {
+ var location = new SourceRange(expr.Location.Start, GetSourceRange(context).End);
+ expr = new UnaryExpression(location, UnaryOperator.PostDecrement, expr, false);
+ }
+ }
+
+ return expr;
+ }
+
+ private Expression? BuildCastExpression(Java9Parser.CastExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+
+ if (context.primitiveType() != null)
+ {
+ var type = BuildPrimitiveType(context.primitiveType());
+ var expr = BuildUnaryExpression(context.unaryExpression());
+
+ if (type != null && expr != null)
+ {
+ return new CastExpression(location, type, expr);
+ }
+ }
+ else if (context.referenceType() != null)
+ {
+ var type = BuildTypeReference(context.referenceType());
+ var expr = context.unaryExpressionNotPlusMinus() != null
+ ? BuildUnaryExpressionNotPlusMinus(context.unaryExpressionNotPlusMinus())
+ : BuildLambdaExpression(context.lambdaExpression());
+
+ if (type != null && expr != null)
+ {
+ return new CastExpression(location, type, expr);
+ }
+ }
+
+ return null;
+ }
+
+ private Expression? BuildPrimary(Java9Parser.PrimaryContext context)
+ {
+ if (context.primaryNoNewArray_lfno_primary() != null)
+ {
+ return BuildPrimaryNoNewArray(context.primaryNoNewArray_lfno_primary());
+ }
+ else if (context.arrayCreationExpression() != null)
+ {
+ return BuildArrayCreationExpression(context.arrayCreationExpression());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildPrimaryNoNewArray(Java9Parser.PrimaryNoNewArray_lfno_primaryContext context)
+ {
+ if (context.literal() != null)
+ {
+ return BuildLiteral(context.literal());
+ }
+ else if (context.CLASS() != null)
+ {
+ // Handle class literal
+ var location = GetSourceRange(context);
+ TypeReference? type = null;
+
+ if (context.typeName() != null)
+ {
+ type = BuildTypeName(context.typeName());
+ // Handle array dimensions
+ var dimsCount = context.LBRACK()?.Length ?? 0;
+ if (dimsCount > 0 && type != null)
+ {
+ type = new ArrayType(type.Location, type, dimsCount);
+ }
+ }
+ else if (context.unannPrimitiveType() != null)
+ {
+ var primitiveType = ParsePrimitiveTypeKind(context.unannPrimitiveType().GetText());
+ type = new PrimitiveType(GetSourceRange(context.unannPrimitiveType()), primitiveType);
+ // Handle array dimensions
+ var dimsCount = context.LBRACK()?.Length ?? 0;
+ if (dimsCount > 0)
+ {
+ type = new ArrayType(type.Location, type, dimsCount);
+ }
+ }
+ else if (context.VOID() != null)
+ {
+ type = new PrimitiveType(GetSourceRange(context), PrimitiveTypeKind.Void);
+ }
+
+ return type != null ? new ClassLiteralExpression(location, type) : null;
+ }
+ else if (context.GetText() == "this")
+ {
+ return new ThisExpression(GetSourceRange(context));
+ }
+ else if (context.typeName() != null && context.GetChild(context.ChildCount - 1).GetText() == "this")
+ {
+ var qualifier = BuildExpressionName(context.typeName());
+ return new ThisExpression(GetSourceRange(context), qualifier);
+ }
+ else if (context.expression() != null)
+ {
+ // Parenthesized expression
+ return BuildExpression(context.expression());
+ }
+ else if (context.classInstanceCreationExpression_lfno_primary() != null)
+ {
+ return BuildClassInstanceCreationExpression(context.classInstanceCreationExpression_lfno_primary());
+ }
+ else if (context.fieldAccess_lfno_primary() != null)
+ {
+ return BuildFieldAccess(context.fieldAccess_lfno_primary());
+ }
+ else if (context.arrayAccess_lfno_primary() != null)
+ {
+ return BuildArrayAccess(context.arrayAccess_lfno_primary());
+ }
+ else if (context.methodInvocation_lfno_primary() != null)
+ {
+ return BuildMethodInvocation(context.methodInvocation_lfno_primary());
+ }
+ else if (context.methodReference_lfno_primary() != null)
+ {
+ return BuildMethodReference(context.methodReference_lfno_primary());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildLiteral(Java9Parser.LiteralContext context)
+ {
+ var location = GetSourceRange(context);
+ var text = context.GetText();
+
+ if (context.IntegerLiteral() != null)
+ {
+ if (int.TryParse(text.TrimEnd('l', 'L'), out int intValue))
+ {
+ return new LiteralExpression(location, intValue, LiteralKind.Integer);
+ }
+ else if (long.TryParse(text.TrimEnd('l', 'L'), out long longValue))
+ {
+ return new LiteralExpression(location, longValue, LiteralKind.Long);
+ }
+ }
+ else if (context.FloatingPointLiteral() != null)
+ {
+ if (text.EndsWith('f') || text.EndsWith('F'))
+ {
+ if (float.TryParse(text.TrimEnd('f', 'F'), out float floatValue))
+ {
+ return new LiteralExpression(location, floatValue, LiteralKind.Float);
+ }
+ }
+ else if (double.TryParse(text.TrimEnd('d', 'D'), out double doubleValue))
+ {
+ return new LiteralExpression(location, doubleValue, LiteralKind.Double);
+ }
+ }
+ else if (context.BooleanLiteral() != null)
+ {
+ var boolValue = text == "true";
+ return new LiteralExpression(location, boolValue, LiteralKind.Boolean);
+ }
+ else if (context.CharacterLiteral() != null)
+ {
+ var charValue = UnescapeCharacterLiteral(text);
+ return new LiteralExpression(location, charValue, LiteralKind.Character);
+ }
+ else if (context.StringLiteral() != null)
+ {
+ var stringValue = UnescapeStringLiteral(text);
+ return new LiteralExpression(location, stringValue, LiteralKind.String);
+ }
+ else if (context.NullLiteral() != null)
+ {
+ return new LiteralExpression(location, null, LiteralKind.Null);
+ }
+
+ return null;
+ }
+
+ private char UnescapeCharacterLiteral(string literal)
+ {
+ // Remove quotes
+ literal = literal.Substring(1, literal.Length - 2);
+
+ if (literal.Length == 1) return literal[0];
+
+ // Handle escape sequences
+ return literal[1] switch
+ {
+ 'b' => '\b',
+ 't' => '\t',
+ 'n' => '\n',
+ 'f' => '\f',
+ 'r' => '\r',
+ '\"' => '\"',
+ '\'' => '\'',
+ '\\' => '\\',
+ _ => literal[1]
+ };
+ }
+
+ private string UnescapeStringLiteral(string literal)
+ {
+ // Remove quotes
+ literal = literal.Substring(1, literal.Length - 2);
+
+ // Handle escape sequences
+ return literal
+ .Replace("\\b", "\b")
+ .Replace("\\t", "\t")
+ .Replace("\\n", "\n")
+ .Replace("\\f", "\f")
+ .Replace("\\r", "\r")
+ .Replace("\\\"", "\"")
+ .Replace("\\'", "'")
+ .Replace("\\\\", "\\");
+ }
+
+ private Expression? BuildClassLiteral(Java9Parser.ClassLiteralContext context)
+ {
+ var location = GetSourceRange(context);
+ TypeReference? type = null;
+
+ if (context.typeName() != null)
+ {
+ type = BuildTypeName(context.typeName());
+
+ // Handle array dimensions
+ var dimsCount = context.children.Count(c => c.GetText() == "[");
+ if (dimsCount > 0 && type != null)
+ {
+ type = new ArrayType(location, type, dimsCount);
+ }
+ }
+ else if (context.numericType() != null)
+ {
+ type = BuildNumericType(context.numericType());
+
+ // Handle array dimensions
+ var dimsCount = context.children.Count(c => c.GetText() == "[");
+ if (dimsCount > 0 && type != null)
+ {
+ type = new ArrayType(location, type, dimsCount);
+ }
+ }
+ else if (context.GetText() == "boolean.class")
+ {
+ type = new PrimitiveType(location, PrimitiveTypeKind.Boolean);
+ }
+ else if (context.GetText() == "void.class")
+ {
+ type = new PrimitiveType(location, PrimitiveTypeKind.Void);
+ }
+
+ return type != null ? new ClassLiteralExpression(location, type) : null;
+ }
+
+ private PrimitiveType? BuildNumericType(Java9Parser.NumericTypeContext context)
+ {
+ var location = GetSourceRange(context);
+ var text = context.GetText();
+
+ var kind = text switch
+ {
+ "byte" => PrimitiveTypeKind.Byte,
+ "short" => PrimitiveTypeKind.Short,
+ "int" => PrimitiveTypeKind.Int,
+ "long" => PrimitiveTypeKind.Long,
+ "char" => PrimitiveTypeKind.Char,
+ "float" => PrimitiveTypeKind.Float,
+ "double" => PrimitiveTypeKind.Double,
+ _ => (PrimitiveTypeKind?)null
+ };
+
+ return kind.HasValue ? new PrimitiveType(location, kind.Value) : null;
+ }
+
+ private Expression? BuildExpressionName(IParseTree context)
+ {
+ if (context is Java9Parser.TypeNameContext typeName)
+ {
+ // TypeName has a recursive structure
+ var location = GetSourceRange(typeName);
+ return new IdentifierExpression(location, typeName.GetText());
+ }
+ else if (context is Java9Parser.ExpressionNameContext exprName)
+ {
+ // ExpressionName has a recursive structure
+ var location = GetSourceRange(exprName);
+ return new IdentifierExpression(location, exprName.GetText());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildClassInstanceCreationExpression(Java9Parser.ClassInstanceCreationExpression_lfno_primaryContext context)
+ {
+ var location = GetSourceRange(context);
+ var typeArgs = BuildTypeArguments(context.typeArguments());
+ var annotations = BuildAnnotations(context.annotation());
+ var identifiers = context.identifier();
+
+ ClassOrInterfaceType? type = null;
+ foreach (var id in identifiers)
+ {
+ var idLocation = GetSourceRange(id);
+ type = new ClassOrInterfaceType(idLocation, id.GetText(), type,
+ id == identifiers.Last() ? typeArgs : new List(),
+ annotations);
+ }
+
+ if (type == null) return null;
+
+ var arguments = context.argumentList() != null
+ ? context.argumentList().expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList()
+ : new List();
+
+ ClassDeclaration? anonymousBody = null;
+ if (context.classBody() != null)
+ {
+ var members = BuildClassMembers(context.classBody());
+ anonymousBody = new ClassDeclaration(
+ GetSourceRange(context.classBody()),
+ "", // Anonymous
+ Modifiers.None,
+ new List(),
+ new List(),
+ type,
+ new List(),
+ members,
+ null
+ );
+ }
+
+ return new NewExpression(location, type, arguments, anonymousBody);
+ }
+
+ private Expression? BuildFieldAccess(Java9Parser.FieldAccess_lfno_primaryContext context)
+ {
+ var location = GetSourceRange(context);
+ Expression? target = null;
+
+ if (context.GetChild(0).GetText() == "super")
+ {
+ var childContext = context.GetChild(0) as ParserRuleContext;
+ if (childContext != null)
+ {
+ target = new SuperExpression(GetSourceRange(childContext));
+ }
+ }
+ else if (context.typeName() != null)
+ {
+ var qualifier = BuildExpressionName(context.typeName());
+ target = new SuperExpression(location, qualifier);
+ }
+
+ if (target != null && context.identifier() != null)
+ {
+ return new FieldAccessExpression(location, target, context.identifier().GetText());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildFieldAccess(Java9Parser.FieldAccessContext context)
+ {
+ var location = GetSourceRange(context);
+ var target = BuildPrimary(context.primary());
+
+ if (target != null && context.identifier() != null)
+ {
+ return new FieldAccessExpression(location, target, context.identifier().GetText());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildArrayAccess(Java9Parser.ArrayAccess_lfno_primaryContext context)
+ {
+ var location = GetSourceRange(context);
+ var array = BuildExpressionName(context.expressionName());
+ var indices = context.expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList();
+
+ if (array == null || indices.Count == 0) return null;
+
+ Expression result = array;
+ foreach (var index in indices)
+ {
+ result = new ArrayAccessExpression(location, result, index);
+ }
+
+ return result;
+ }
+
+ private Expression? BuildArrayAccess(Java9Parser.ArrayAccessContext context)
+ {
+ var location = GetSourceRange(context);
+ Expression? array = null;
+
+ if (context.expressionName() != null)
+ {
+ array = BuildExpressionName(context.expressionName());
+ }
+ else if (context.primaryNoNewArray_lfno_arrayAccess() != null)
+ {
+ // Complex array access - simplified for now
+ array = BuildExpression(context.primaryNoNewArray_lfno_arrayAccess());
+ }
+
+ if (array == null) return null;
+
+ var indices = context.expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList();
+
+ Expression result = array;
+ foreach (var index in indices)
+ {
+ result = new ArrayAccessExpression(location, result, index);
+ }
+
+ return result;
+ }
+
+ private Expression? BuildMethodInvocation(Java9Parser.MethodInvocation_lfno_primaryContext context)
+ {
+ var location = GetSourceRange(context);
+ Expression? target = null;
+ string? methodName = null;
+ List typeArgs = new();
+
+ if (context.methodName() != null)
+ {
+ // Simple method name
+ methodName = context.methodName().identifier().GetText();
+ }
+ else if (context.typeName() != null)
+ {
+ // TypeName.method or TypeName.super.method
+ target = BuildExpressionName(context.typeName());
+
+ if (context.identifier() != null)
+ {
+ methodName = context.identifier().GetText();
+ }
+ else if (context.GetChild(context.ChildCount - 3)?.GetText() == "super")
+ {
+ target = new SuperExpression(location, target);
+ methodName = context.identifier().GetText();
+ }
+ }
+ else if (context.expressionName() != null)
+ {
+ // ExpressionName.method or ExpressionName.super.method
+ target = BuildExpressionName(context.expressionName());
+
+ if (context.identifier() != null)
+ {
+ methodName = context.identifier().GetText();
+ }
+ else if (context.GetChild(context.ChildCount - 3)?.GetText() == "super")
+ {
+ target = new SuperExpression(location, target);
+ methodName = context.identifier().GetText();
+ }
+ }
+ else if (context.GetChild(0).GetText() == "super")
+ {
+ // super.method
+ var childContext = context.GetChild(0) as ParserRuleContext;
+ if (childContext != null)
+ {
+ target = new SuperExpression(GetSourceRange(childContext));
+ }
+ methodName = context.identifier().GetText();
+ }
+
+ if (methodName == null) return null;
+
+ // Type arguments
+ if (context.typeArguments() != null)
+ {
+ typeArgs = BuildTypeArguments(context.typeArguments());
+ }
+
+ // Arguments
+ var arguments = context.argumentList() != null
+ ? context.argumentList().expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList()
+ : new List();
+
+ return new MethodCallExpression(location, target, methodName, typeArgs, arguments);
+ }
+
+ private Expression? BuildMethodReference(Java9Parser.MethodReference_lfno_primaryContext context)
+ {
+ var location = GetSourceRange(context);
+ Expression? target = null;
+ string? methodName = null;
+ List typeArgs = new();
+
+ if (context.expressionName() != null)
+ {
+ target = BuildExpressionName(context.expressionName());
+ }
+ else if (context.referenceType() != null)
+ {
+ var type = BuildTypeReference(context.referenceType());
+ if (type != null)
+ {
+ target = new ClassLiteralExpression(location, type);
+ }
+ }
+ else if (context.GetChild(0).GetText() == "super")
+ {
+ var childContext = context.GetChild(0) as ParserRuleContext;
+ if (childContext != null)
+ {
+ target = new SuperExpression(GetSourceRange(childContext));
+ }
+ }
+ else if (context.typeName() != null)
+ {
+ var qualifier = BuildExpressionName(context.typeName());
+ target = new SuperExpression(location, qualifier);
+ }
+
+ if (target == null) return null;
+
+ // Type arguments
+ if (context.typeArguments() != null)
+ {
+ typeArgs = BuildTypeArguments(context.typeArguments());
+ }
+
+ // Method name
+ if (context.identifier() != null)
+ {
+ methodName = context.identifier().GetText();
+ }
+ else if (context.GetChild(context.ChildCount - 1).GetText() == "new")
+ {
+ methodName = "new";
+ }
+
+ if (methodName == null) return null;
+
+ return new MethodReferenceExpression(location, target, methodName, typeArgs);
+ }
+
+ private Expression? BuildArrayCreationExpression(Java9Parser.ArrayCreationExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+ TypeReference? elementType = null;
+ List dimensions = new();
+ ArrayInitializer? initializer = null;
+
+ if (context.primitiveType() != null)
+ {
+ elementType = BuildPrimitiveType(context.primitiveType());
+ }
+ else if (context.classOrInterfaceType() != null)
+ {
+ elementType = BuildClassOrInterfaceType(context.classOrInterfaceType());
+ }
+
+ if (elementType == null) return null;
+
+ // Dimensions with expressions
+ if (context.dimExprs() != null)
+ {
+ foreach (var dimExpr in context.dimExprs().dimExpr())
+ {
+ var expr = BuildExpression(dimExpr.expression());
+ if (expr != null) dimensions.Add(expr);
+ }
+ }
+
+ // Array initializer
+ if (context.arrayInitializer() != null)
+ {
+ initializer = BuildArrayInitializer(context.arrayInitializer());
+ }
+
+ return new NewArrayExpression(location, elementType, dimensions, initializer);
+ }
+
+ private ArrayInitializer? BuildArrayInitializer(Java9Parser.ArrayInitializerContext context)
+ {
+ var location = GetSourceRange(context);
+ var elements = new List();
+
+ if (context.variableInitializerList() != null)
+ {
+ foreach (var init in context.variableInitializerList().variableInitializer())
+ {
+ var expr = BuildVariableInitializer(init);
+ if (expr != null) elements.Add(expr);
+ }
+ }
+
+ return new ArrayInitializer(location, elements);
+ }
+
+ private Expression? BuildVariableInitializer(Java9Parser.VariableInitializerContext context)
+ {
+ if (context.expression() != null)
+ {
+ return BuildExpression(context.expression());
+ }
+ else if (context.arrayInitializer() != null)
+ {
+ return BuildArrayInitializer(context.arrayInitializer());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildLambdaExpression(Java9Parser.LambdaExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+ var parameters = BuildLambdaParameters(context.lambdaParameters());
+ JavaNode? body = null;
+
+ if (context.lambdaBody().expression() != null)
+ {
+ body = BuildExpression(context.lambdaBody().expression());
+ }
+ else if (context.lambdaBody().block() != null)
+ {
+ body = BuildBlock(context.lambdaBody().block());
+ }
+
+ return body != null ? new LambdaExpression(location, parameters, body) : null;
+ }
+
+ private List BuildLambdaParameters(Java9Parser.LambdaParametersContext context)
+ {
+ var parameters = new List();
+
+ if (context.identifier() != null)
+ {
+ // Single parameter without parentheses
+ var location = GetSourceRange(context.identifier());
+ parameters.Add(new LambdaParameter(location, context.identifier().GetText()));
+ }
+ else if (context.formalParameterList() != null)
+ {
+ // Formal parameters with types
+ var formalParams = BuildParameters(context.formalParameterList());
+ foreach (var param in formalParams)
+ {
+ parameters.Add(new LambdaParameter(
+ param.Location,
+ param.Name,
+ param.Type,
+ param.IsFinal
+ ));
+ }
+ }
+ else if (context.inferredFormalParameterList() != null)
+ {
+ // Inferred parameters without types
+ foreach (var id in context.inferredFormalParameterList().identifier())
+ {
+ var location = GetSourceRange(id);
+ parameters.Add(new LambdaParameter(location, id.GetText()));
+ }
+ }
+
+ 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();
+
+ 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
+
+ private BlockStatement BuildBlockFromStatements(Java9Parser.BlockStatementsContext blockStatements)
+ {
+ var statements = new List();
+ foreach (var stmt in blockStatements.blockStatement())
+ {
+ var statement = BuildBlockStatement(stmt);
+ if (statement != null) statements.Add(statement);
+ }
+
+ return new BlockStatement(GetSourceRange(blockStatements), statements);
+ }
+
+ private BlockStatement? BuildBlock(Java9Parser.BlockContext context)
+ {
+ var location = GetSourceRange(context);
+ var statements = new List();
+
+ if (context.blockStatements() != null)
+ {
+ foreach (var stmt in context.blockStatements().blockStatement())
+ {
+ var statement = BuildBlockStatement(stmt);
+ if (statement != null) statements.Add(statement);
+ }
+ }
+
+ return new BlockStatement(location, statements);
+ }
+
+ private Statement? BuildBlockStatement(Java9Parser.BlockStatementContext context)
+ {
+ if (context.localVariableDeclarationStatement() != null)
+ {
+ return BuildLocalVariableDeclarationStatement(context.localVariableDeclarationStatement());
+ }
+ else if (context.classDeclaration() != null)
+ {
+ // Local class declaration - we'll skip this for now
+ return null;
+ }
+ else if (context.statement() != null)
+ {
+ return BuildStatement(context.statement());
+ }
+
+ return null;
+ }
+
+ private Statement? BuildLocalVariableDeclarationStatement(Java9Parser.LocalVariableDeclarationStatementContext context)
+ {
+ return BuildLocalVariableDeclaration(context.localVariableDeclaration());
+ }
+
+ private LocalVariableStatement? BuildLocalVariableDeclaration(Java9Parser.LocalVariableDeclarationContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.variableModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var variables = context.variableDeclaratorList().variableDeclarator()
+ .Select(v => BuildVariableDeclarator(v))
+ .Where(v => v != null)
+ .Cast()
+ .ToList();
+
+ var isFinal = modifiers.HasFlag(Modifiers.Final);
+
+ return new LocalVariableStatement(location, type, variables, isFinal);
+ }
+
+ private Statement? BuildStatement(Java9Parser.StatementContext context)
+ {
+ if (context.statementWithoutTrailingSubstatement() != null)
+ {
+ return BuildStatementWithoutTrailingSubstatement(context.statementWithoutTrailingSubstatement());
+ }
+ else if (context.labeledStatement() != null)
+ {
+ return BuildLabeledStatement(context.labeledStatement());
+ }
+ else if (context.ifThenStatement() != null)
+ {
+ return BuildIfStatement(context.ifThenStatement());
+ }
+ else if (context.ifThenElseStatement() != null)
+ {
+ return BuildIfElseStatement(context.ifThenElseStatement());
+ }
+ else if (context.whileStatement() != null)
+ {
+ return BuildWhileStatement(context.whileStatement());
+ }
+ else if (context.forStatement() != null)
+ {
+ return BuildForStatement(context.forStatement());
+ }
+
+ return null;
+ }
+
+ private Statement? BuildStatementWithoutTrailingSubstatement(Java9Parser.StatementWithoutTrailingSubstatementContext context)
+ {
+ if (context.block() != null)
+ {
+ return BuildBlock(context.block());
+ }
+ else if (context.emptyStatement_() != null)
+ {
+ return new EmptyStatement(GetSourceRange(context.emptyStatement_()));
+ }
+ else if (context.expressionStatement() != null)
+ {
+ return BuildExpressionStatement(context.expressionStatement());
+ }
+ else if (context.assertStatement() != null)
+ {
+ return BuildAssertStatement(context.assertStatement());
+ }
+ else if (context.switchStatement() != null)
+ {
+ return BuildSwitchStatement(context.switchStatement());
+ }
+ else if (context.doStatement() != null)
+ {
+ return BuildDoStatement(context.doStatement());
+ }
+ else if (context.breakStatement() != null)
+ {
+ return BuildBreakStatement(context.breakStatement());
+ }
+ else if (context.continueStatement() != null)
+ {
+ return BuildContinueStatement(context.continueStatement());
+ }
+ else if (context.returnStatement() != null)
+ {
+ return BuildReturnStatement(context.returnStatement());
+ }
+ else if (context.synchronizedStatement() != null)
+ {
+ return BuildSynchronizedStatement(context.synchronizedStatement());
+ }
+ else if (context.throwStatement() != null)
+ {
+ return BuildThrowStatement(context.throwStatement());
+ }
+ else if (context.tryStatement() != null)
+ {
+ return BuildTryStatement(context.tryStatement());
+ }
+
+ return null;
+ }
+
+ private ExpressionStatement? BuildExpressionStatement(Java9Parser.ExpressionStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var expr = BuildExpression(context.statementExpression());
+ return expr != null ? new ExpressionStatement(location, expr) : null;
+ }
+
+ private Expression? BuildExpression(Java9Parser.StatementExpressionContext context)
+ {
+ if (context.assignment() != null)
+ {
+ return BuildAssignment(context.assignment());
+ }
+ else if (context.preIncrementExpression() != null)
+ {
+ return BuildPreIncrementExpression(context.preIncrementExpression());
+ }
+ else if (context.preDecrementExpression() != null)
+ {
+ return BuildPreDecrementExpression(context.preDecrementExpression());
+ }
+ else if (context.postIncrementExpression() != null)
+ {
+ return BuildPostIncrementExpression(context.postIncrementExpression());
+ }
+ else if (context.postDecrementExpression() != null)
+ {
+ return BuildPostDecrementExpression(context.postDecrementExpression());
+ }
+ else if (context.methodInvocation() != null)
+ {
+ return BuildMethodInvocation(context.methodInvocation());
+ }
+ else if (context.classInstanceCreationExpression() != null)
+ {
+ return BuildClassInstanceCreationExpression(context.classInstanceCreationExpression());
+ }
+
+ return null;
+ }
+
+ private Expression? BuildPostIncrementExpression(Java9Parser.PostIncrementExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildPostfixExpression(context.postfixExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.PostIncrement, operand, false)
+ : null;
+ }
+
+ private Expression? BuildPostDecrementExpression(Java9Parser.PostDecrementExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+ var operand = BuildPostfixExpression(context.postfixExpression());
+ return operand != null
+ ? new UnaryExpression(location, UnaryOperator.PostDecrement, operand, false)
+ : null;
+ }
+
+ private Expression? BuildMethodInvocation(Java9Parser.MethodInvocationContext context)
+ {
+ var location = GetSourceRange(context);
+ Expression? target = null;
+ string methodName;
+ List typeArgs = new List();
+
+ // Handle different method invocation patterns
+ if (context.methodName() != null)
+ {
+ // Simple method call
+ methodName = context.methodName().GetText();
+ }
+ else if (context.typeName() != null && context.identifier() != null)
+ {
+ // Qualified method call
+ target = BuildExpressionName(context.typeName());
+ methodName = context.identifier().GetText();
+ if (context.typeArguments() != null)
+ {
+ typeArgs = BuildTypeArguments(context.typeArguments());
+ }
+ }
+ else if (context.expressionName() != null && context.identifier() != null)
+ {
+ // Expression.method() call
+ target = BuildExpressionName(context.expressionName());
+ methodName = context.identifier().GetText();
+ if (context.typeArguments() != null)
+ {
+ typeArgs = BuildTypeArguments(context.typeArguments());
+ }
+ }
+ else if (context.primary() != null && context.identifier() != null)
+ {
+ // primary.method() call
+ target = BuildPrimary(context.primary());
+ methodName = context.identifier().GetText();
+ if (context.typeArguments() != null)
+ {
+ typeArgs = BuildTypeArguments(context.typeArguments());
+ }
+ }
+ else if (context.SUPER() != null && context.identifier() != null)
+ {
+ // super.method() call
+ target = new SuperExpression(GetSourceRange(context));
+ methodName = context.identifier().GetText();
+ if (context.typeArguments() != null)
+ {
+ typeArgs = BuildTypeArguments(context.typeArguments());
+ }
+ }
+ else
+ {
+ // Fallback
+ methodName = "unknown";
+ }
+
+ // Arguments
+ var arguments = context.argumentList() != null
+ ? context.argumentList().expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList()
+ : new List();
+
+ return new MethodCallExpression(location, target, methodName, typeArgs, arguments);
+ }
+
+ private Expression? BuildClassInstanceCreationExpression(Java9Parser.ClassInstanceCreationExpressionContext context)
+ {
+ var location = GetSourceRange(context);
+
+ // Build the type being instantiated
+ TypeReference? type = null;
+ var identifiers = context.identifier();
+ if (identifiers != null && identifiers.Length > 0)
+ {
+ var typeName = string.Join(".", identifiers.Select(id => id.GetText()));
+ var typeArgs = context.typeArguments() != null
+ ? BuildTypeArguments(context.typeArguments())
+ : new List();
+ type = new ClassOrInterfaceType(location, typeName, null, typeArgs, new List());
+ }
+
+ if (type == null) return null;
+
+ // Build arguments
+ var arguments = context.argumentList() != null
+ ? context.argumentList().expression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList()
+ : new List();
+
+ // Handle anonymous class body if present
+ ClassDeclaration? anonymousBody = null;
+ if (context.classBody() != null)
+ {
+ var members = BuildClassMembers(context.classBody());
+ anonymousBody = new ClassDeclaration(
+ location,
+ "$Anonymous",
+ Modifiers.None,
+ new List(),
+ new List(),
+ type,
+ new List(),
+ members,
+ null
+ );
+ }
+
+ return new NewExpression(location, type as ClassOrInterfaceType ??
+ new ClassOrInterfaceType(location, "Unknown", null, new List(), new List()),
+ arguments, anonymousBody);
+ }
+
+ private IfStatement? BuildIfStatement(Java9Parser.IfThenStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var condition = BuildExpression(context.expression());
+ var thenStmt = BuildStatement(context.statement());
+
+ if (condition != null && thenStmt != null)
+ {
+ return new IfStatement(location, condition, thenStmt);
+ }
+
+ return null;
+ }
+
+ private IfStatement? BuildIfElseStatement(Java9Parser.IfThenElseStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var condition = BuildExpression(context.expression());
+ var thenStmt = BuildStatement(context.statementNoShortIf());
+ var elseStmt = BuildStatement(context.statement());
+
+ if (condition != null && thenStmt != null)
+ {
+ return new IfStatement(location, condition, thenStmt, elseStmt);
+ }
+
+ return null;
+ }
+
+ private Statement? BuildStatement(Java9Parser.StatementNoShortIfContext context)
+ {
+ if (context.statementWithoutTrailingSubstatement() != null)
+ {
+ return BuildStatementWithoutTrailingSubstatement(context.statementWithoutTrailingSubstatement());
+ }
+ else if (context.labeledStatementNoShortIf() != null)
+ {
+ return BuildLabeledStatementNoShortIf(context.labeledStatementNoShortIf());
+ }
+ else if (context.ifThenElseStatementNoShortIf() != null)
+ {
+ return BuildIfElseStatementNoShortIf(context.ifThenElseStatementNoShortIf());
+ }
+ else if (context.whileStatementNoShortIf() != null)
+ {
+ return BuildWhileStatementNoShortIf(context.whileStatementNoShortIf());
+ }
+ else if (context.forStatementNoShortIf() != null)
+ {
+ return BuildForStatementNoShortIf(context.forStatementNoShortIf());
+ }
+
+ return null;
+ }
+
+ private IfStatement? BuildIfElseStatementNoShortIf(Java9Parser.IfThenElseStatementNoShortIfContext context)
+ {
+ var location = GetSourceRange(context);
+ var condition = BuildExpression(context.expression());
+ var thenStmt = BuildStatement(context.statementNoShortIf()[0]);
+ var elseStmt = BuildStatement(context.statementNoShortIf()[1]);
+
+ if (condition != null && thenStmt != null)
+ {
+ return new IfStatement(location, condition, thenStmt, elseStmt);
+ }
+
+ return null;
+ }
+
+ private WhileStatement? BuildWhileStatement(Java9Parser.WhileStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var condition = BuildExpression(context.expression());
+ var body = BuildStatement(context.statement());
+
+ if (condition != null && body != null)
+ {
+ return new WhileStatement(location, condition, body);
+ }
+
+ return null;
+ }
+
+ private WhileStatement? BuildWhileStatementNoShortIf(Java9Parser.WhileStatementNoShortIfContext context)
+ {
+ var location = GetSourceRange(context);
+ var condition = BuildExpression(context.expression());
+ var body = BuildStatement(context.statementNoShortIf());
+
+ if (condition != null && body != null)
+ {
+ return new WhileStatement(location, condition, body);
+ }
+
+ return null;
+ }
+
+ private DoWhileStatement? BuildDoStatement(Java9Parser.DoStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var body = BuildStatement(context.statement());
+ var condition = BuildExpression(context.expression());
+
+ if (body != null && condition != null)
+ {
+ return new DoWhileStatement(location, body, condition);
+ }
+
+ return null;
+ }
+
+ private Statement? BuildForStatement(Java9Parser.ForStatementContext context)
+ {
+ if (context.basicForStatement() != null)
+ {
+ return BuildBasicForStatement(context.basicForStatement());
+ }
+ else if (context.enhancedForStatement() != null)
+ {
+ return BuildEnhancedForStatement(context.enhancedForStatement());
+ }
+
+ return null;
+ }
+
+ private Statement? BuildForStatementNoShortIf(Java9Parser.ForStatementNoShortIfContext context)
+ {
+ if (context.basicForStatementNoShortIf() != null)
+ {
+ return BuildBasicForStatementNoShortIf(context.basicForStatementNoShortIf());
+ }
+ else if (context.enhancedForStatementNoShortIf() != null)
+ {
+ return BuildEnhancedForStatementNoShortIf(context.enhancedForStatementNoShortIf());
+ }
+
+ return null;
+ }
+
+ private ForStatement? BuildBasicForStatement(Java9Parser.BasicForStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var initializers = new List();
+ Expression? condition = null;
+ var updates = new List();
+
+ if (context.forInit() != null)
+ {
+ initializers = BuildForInit(context.forInit());
+ }
+
+ if (context.expression() != null)
+ {
+ condition = BuildExpression(context.expression());
+ }
+
+ if (context.forUpdate() != null)
+ {
+ updates = BuildForUpdate(context.forUpdate());
+ }
+
+ var body = BuildStatement(context.statement());
+ if (body == null) return null;
+
+ return new ForStatement(location, initializers, condition, updates, body);
+ }
+
+ private ForStatement? BuildBasicForStatementNoShortIf(Java9Parser.BasicForStatementNoShortIfContext context)
+ {
+ var location = GetSourceRange(context);
+ var initializers = new List();
+ Expression? condition = null;
+ var updates = new List();
+
+ if (context.forInit() != null)
+ {
+ initializers = BuildForInit(context.forInit());
+ }
+
+ if (context.expression() != null)
+ {
+ condition = BuildExpression(context.expression());
+ }
+
+ if (context.forUpdate() != null)
+ {
+ updates = BuildForUpdate(context.forUpdate());
+ }
+
+ var body = BuildStatement(context.statementNoShortIf());
+ if (body == null) return null;
+
+ return new ForStatement(location, initializers, condition, updates, body);
+ }
+
+ private List BuildForInit(Java9Parser.ForInitContext context)
+ {
+ var statements = new List();
+
+ if (context.statementExpressionList() != null)
+ {
+ foreach (var expr in context.statementExpressionList().statementExpression())
+ {
+ var expression = BuildExpression(expr);
+ if (expression != null)
+ {
+ statements.Add(new ExpressionStatement(expression.Location, expression));
+ }
+ }
+ }
+ else if (context.localVariableDeclaration() != null)
+ {
+ var varDecl = BuildLocalVariableDeclaration(context.localVariableDeclaration());
+ if (varDecl != null) statements.Add(varDecl);
+ }
+
+ return statements;
+ }
+
+ private List BuildForUpdate(Java9Parser.ForUpdateContext context)
+ {
+ return context.statementExpressionList().statementExpression()
+ .Select(e => BuildExpression(e))
+ .Where(e => e != null)
+ .Cast()
+ .ToList();
+ }
+
+ private ForEachStatement? BuildEnhancedForStatement(Java9Parser.EnhancedForStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.variableModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var varId = context.variableDeclaratorId();
+ var varName = varId.identifier().GetText();
+
+ // Handle array dimensions on variable name
+ if (varId.dims() != null)
+ {
+ var dimensions = varId.dims().GetText().Length / 2;
+ type = new ArrayType(location, type, dimensions);
+ }
+
+ var iterable = BuildExpression(context.expression());
+ var body = BuildStatement(context.statement());
+
+ if (iterable != null && body != null)
+ {
+ return new ForEachStatement(location, type, varName, iterable, body, modifiers.HasFlag(Modifiers.Final));
+ }
+
+ return null;
+ }
+
+ private ForEachStatement? BuildEnhancedForStatementNoShortIf(Java9Parser.EnhancedForStatementNoShortIfContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.variableModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var varId = context.variableDeclaratorId();
+ var varName = varId.identifier().GetText();
+
+ // Handle array dimensions on variable name
+ if (varId.dims() != null)
+ {
+ var dimensions = varId.dims().GetText().Length / 2;
+ type = new ArrayType(location, type, dimensions);
+ }
+
+ var iterable = BuildExpression(context.expression());
+ var body = BuildStatement(context.statementNoShortIf());
+
+ if (iterable != null && body != null)
+ {
+ return new ForEachStatement(location, type, varName, iterable, body, modifiers.HasFlag(Modifiers.Final));
+ }
+
+ return null;
+ }
+
+ private LabeledStatement? BuildLabeledStatement(Java9Parser.LabeledStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var label = context.identifier().GetText();
+ var statement = BuildStatement(context.statement());
+
+ return statement != null
+ ? new LabeledStatement(location, label, statement)
+ : null;
+ }
+
+ private LabeledStatement? BuildLabeledStatementNoShortIf(Java9Parser.LabeledStatementNoShortIfContext context)
+ {
+ var location = GetSourceRange(context);
+ var label = context.identifier().GetText();
+ var statement = BuildStatement(context.statementNoShortIf());
+
+ return statement != null
+ ? new LabeledStatement(location, label, statement)
+ : null;
+ }
+
+ private BreakStatement BuildBreakStatement(Java9Parser.BreakStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var label = context.identifier()?.GetText();
+ return new BreakStatement(location, label);
+ }
+
+ private ContinueStatement BuildContinueStatement(Java9Parser.ContinueStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var label = context.identifier()?.GetText();
+ return new ContinueStatement(location, label);
+ }
+
+ private ReturnStatement BuildReturnStatement(Java9Parser.ReturnStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var value = context.expression() != null
+ ? BuildExpression(context.expression())
+ : null;
+ return new ReturnStatement(location, value);
+ }
+
+ private ThrowStatement? BuildThrowStatement(Java9Parser.ThrowStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var exception = BuildExpression(context.expression());
+ return exception != null
+ ? new ThrowStatement(location, exception)
+ : null;
+ }
+
+ private SynchronizedStatement? BuildSynchronizedStatement(Java9Parser.SynchronizedStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var lockExpr = BuildExpression(context.expression());
+ var body = BuildBlock(context.block());
+
+ if (lockExpr != null && body != null)
+ {
+ return new SynchronizedStatement(location, lockExpr, body);
+ }
+
+ return null;
+ }
+
+ private TryStatement? BuildTryStatement(Java9Parser.TryStatementContext context)
+ {
+ var location = GetSourceRange(context);
+
+ if (context.tryWithResourcesStatement() != null)
+ {
+ return BuildTryWithResourcesStatement(context.tryWithResourcesStatement());
+ }
+
+ var body = BuildBlock(context.block());
+ if (body == null) return null;
+
+ var catchClauses = new List();
+ if (context.catches() != null)
+ {
+ catchClauses = BuildCatchClauses(context.catches());
+ }
+
+ BlockStatement? finallyBlock = null;
+ if (context.finally_() != null)
+ {
+ finallyBlock = BuildBlock(context.finally_().block());
+ }
+
+ return new TryStatement(location, new List(), body, catchClauses, finallyBlock);
+ }
+
+ private TryStatement? BuildTryWithResourcesStatement(Java9Parser.TryWithResourcesStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var resources = BuildResourceList(context.resourceSpecification());
+ var body = BuildBlock(context.block());
+ if (body == null) return null;
+
+ var catchClauses = new List();
+ if (context.catches() != null)
+ {
+ catchClauses = BuildCatchClauses(context.catches());
+ }
+
+ BlockStatement? finallyBlock = null;
+ if (context.finally_() != null)
+ {
+ finallyBlock = BuildBlock(context.finally_().block());
+ }
+
+ return new TryStatement(location, resources, body, catchClauses, finallyBlock);
+ }
+
+ private List BuildResourceList(Java9Parser.ResourceSpecificationContext context)
+ {
+ var resources = new List();
+
+ if (context.resourceList() != null)
+ {
+ foreach (var resource in context.resourceList().resource())
+ {
+ var decl = BuildResource(resource);
+ if (decl != null) resources.Add(decl);
+ }
+ }
+
+ return resources;
+ }
+
+ private ResourceDeclaration? BuildResource(Java9Parser.ResourceContext context)
+ {
+ var location = GetSourceRange(context);
+ var modifiers = BuildModifiers(context.variableModifier());
+ var type = BuildTypeReference(context.unannType());
+ if (type == null) return null;
+
+ var name = context.variableDeclaratorId().identifier().GetText();
+ var initializer = BuildExpression(context.expression());
+ if (initializer == null) return null;
+
+ return new ResourceDeclaration(location, type, name, initializer, modifiers.HasFlag(Modifiers.Final));
+ }
+
+ private List BuildCatchClauses(Java9Parser.CatchesContext context)
+ {
+ return context.catchClause()
+ .Select(c => BuildCatchClause(c))
+ .Where(c => c != null)
+ .Cast()
+ .ToList();
+ }
+
+ private CatchClause? BuildCatchClause(Java9Parser.CatchClauseContext context)
+ {
+ var location = GetSourceRange(context);
+ var catchParam = context.catchFormalParameter();
+ var exceptionTypes = new List();
+
+ if (catchParam.catchType().unannClassType() != null)
+ {
+ var type = BuildTypeReference(catchParam.catchType().unannClassType());
+ if (type != null) exceptionTypes.Add(type);
+ }
+
+ foreach (var additional in catchParam.catchType().classType())
+ {
+ var type = BuildClassType(additional);
+ if (type != null) exceptionTypes.Add(type);
+ }
+
+ var varName = catchParam.variableDeclaratorId().identifier().GetText();
+ var body = BuildBlock(context.block());
+
+ return body != null
+ ? new CatchClause(location, exceptionTypes, varName, body)
+ : null;
+ }
+
+ private TypeReference? BuildTypeReference(Java9Parser.UnannClassTypeContext context)
+ {
+ // Convert unann class type to regular class type handling
+ var location = GetSourceRange(context);
+ var name = context.identifier().GetText();
+ var typeArgs = BuildTypeArguments(context.typeArguments());
+
+ return new ClassOrInterfaceType(location, name, null, typeArgs, new List());
+ }
+
+ private SwitchStatement? BuildSwitchStatement(Java9Parser.SwitchStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var selector = BuildExpression(context.expression());
+ if (selector == null) return null;
+
+ var cases = BuildSwitchCases(context.switchBlock());
+
+ return new SwitchStatement(location, selector, cases);
+ }
+
+ private List BuildSwitchCases(Java9Parser.SwitchBlockContext context)
+ {
+ var cases = new List();
+
+ if (context.switchBlockStatementGroup() != null)
+ {
+ foreach (var group in context.switchBlockStatementGroup())
+ {
+ var labels = new List();
+ bool isDefault = false;
+
+ foreach (var label in group.switchLabels().switchLabel())
+ {
+ if (label.constantExpression() != null)
+ {
+ var expr = BuildExpression(label.constantExpression());
+ if (expr != null) labels.Add(expr);
+ }
+ else if (label.enumConstantName() != null)
+ {
+ var location = GetSourceRange(label.enumConstantName());
+ var name = label.enumConstantName().identifier().GetText();
+ labels.Add(new IdentifierExpression(location, name));
+ }
+ else if (label.GetChild(0).GetText() == "default")
+ {
+ isDefault = true;
+ }
+ }
+
+ var statements = new List();
+ foreach (var stmt in group.blockStatements().blockStatement())
+ {
+ var statement = BuildBlockStatement(stmt);
+ if (statement != null) statements.Add(statement);
+ }
+
+ var caseLocation = GetSourceRange(group);
+ cases.Add(new SwitchCase(caseLocation, labels, statements, isDefault));
+ }
+ }
+
+ return cases;
+ }
+
+ private Expression? BuildExpression(Java9Parser.ConstantExpressionContext context)
+ {
+ return BuildExpression(context.expression());
+ }
+
+ private AssertStatement? BuildAssertStatement(Java9Parser.AssertStatementContext context)
+ {
+ var location = GetSourceRange(context);
+ var expressions = context.expression();
+
+ if (expressions.Length == 0) return null;
+
+ var condition = BuildExpression(expressions[0]);
+ if (condition == null) return null;
+
+ Expression? message = null;
+ if (expressions.Length > 1)
+ {
+ message = BuildExpression(expressions[1]);
+ }
+
+ return new AssertStatement(location, condition, message);
+ }
+
+ // Helper methods
+
+ private string GetQualifiedName(IList identifiers)
+ {
+ return string.Join(".", identifiers.Select(id => id.GetText()));
+ }
+
+ private JavaDoc? ExtractJavaDoc(ParserRuleContext context)
+ {
+ // Look for JavaDoc comment in the hidden channel before this node
+ var tokenIndex = context.Start.TokenIndex;
+ if (tokenIndex > 0)
+ {
+ var bufferedTokens = _tokens as BufferedTokenStream;
+ var hiddenTokens = bufferedTokens?.GetHiddenTokensToLeft(tokenIndex, Java9Lexer.COMMENT);
+ if (hiddenTokens != null)
+ {
+ foreach (var token in hiddenTokens)
+ {
+ if (token.Text.StartsWith("/**", StringComparison.Ordinal))
+ {
+ return ParseJavaDoc(token);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private JavaDoc ParseJavaDoc(IToken token)
+ {
+ var location = new SourceLocation(
+ token.Line,
+ token.Column,
+ token.StartIndex,
+ token.Text.Length
+ );
+ var range = new SourceRange(location, location);
+
+ var content = token.Text;
+ var tags = new List();
+
+ // Simple JavaDoc parsing - can be enhanced
+ var lines = content.Split('\n');
+ foreach (var line in lines)
+ {
+ var trimmed = line.Trim().TrimStart('*').Trim();
+ if (trimmed.StartsWith('@'))
+ {
+ var parts = trimmed.Split(' ', 3);
+ if (parts.Length >= 2)
+ {
+ var tagName = parts[0];
+ var parameter = parts.Length > 2 ? parts[1] : null;
+ var description = parts.Length > 2 ? parts[2] : (parts.Length > 1 ? parts[1] : "");
+ tags.Add(new JavaDocTag(tagName, parameter, description));
+ }
+ }
+ }
+
+ return new JavaDoc(range, content, tags);
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Comparison/AstComparer.cs b/IronJava.Core/AST/Comparison/AstComparer.cs
new file mode 100644
index 0000000..2308408
--- /dev/null
+++ b/IronJava.Core/AST/Comparison/AstComparer.cs
@@ -0,0 +1,427 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using IronJava.Core.AST.Nodes;
+using IronJava.Core.AST.Visitors;
+
+namespace IronJava.Core.AST.Comparison
+{
+ ///
+ /// Provides equality comparison for AST nodes.
+ ///
+ public class AstEqualityComparer : IEqualityComparer
+ {
+ private readonly bool _ignoreLocation;
+ private readonly bool _ignoreJavaDoc;
+ private readonly bool _ignoreAnnotations;
+
+ public AstEqualityComparer(
+ bool ignoreLocation = true,
+ bool ignoreJavaDoc = false,
+ bool ignoreAnnotations = false)
+ {
+ _ignoreLocation = ignoreLocation;
+ _ignoreJavaDoc = ignoreJavaDoc;
+ _ignoreAnnotations = ignoreAnnotations;
+ }
+
+ public bool Equals(JavaNode? x, JavaNode? y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (x == null || y == null) return false;
+ if (x.GetType() != y.GetType()) return false;
+
+ var comparator = new NodeComparator(_ignoreLocation, _ignoreJavaDoc, _ignoreAnnotations);
+ return comparator.Compare(x, y);
+ }
+
+ public int GetHashCode(JavaNode obj)
+ {
+ if (obj == null) return 0;
+
+ var hasher = new NodeHasher(_ignoreLocation, _ignoreJavaDoc, _ignoreAnnotations);
+ return hasher.GetHashCode(obj);
+ }
+ }
+
+ ///
+ /// Internal visitor for comparing nodes.
+ ///
+ internal class NodeComparator : JavaVisitorBase
+ {
+ private readonly bool _ignoreLocation;
+ private readonly bool _ignoreJavaDoc;
+ private readonly bool _ignoreAnnotations;
+ private JavaNode? _other;
+
+ public NodeComparator(bool ignoreLocation, bool ignoreJavaDoc, bool ignoreAnnotations)
+ {
+ _ignoreLocation = ignoreLocation;
+ _ignoreJavaDoc = ignoreJavaDoc;
+ _ignoreAnnotations = ignoreAnnotations;
+ }
+
+ public bool Compare(JavaNode x, JavaNode y)
+ {
+ _other = y;
+ return x.Accept(this);
+ }
+
+ protected override bool DefaultVisit(JavaNode node)
+ {
+ return false;
+ }
+
+ private bool CompareLocation(SourceRange x, SourceRange y)
+ {
+ if (_ignoreLocation) return true;
+ return x.Start.Line == y.Start.Line &&
+ x.Start.Column == y.Start.Column &&
+ x.End.Line == y.End.Line &&
+ x.End.Column == y.End.Column;
+ }
+
+ private bool CompareAnnotations(IReadOnlyList x, IReadOnlyList y)
+ {
+ if (_ignoreAnnotations) return true;
+ if (x.Count != y.Count) return false;
+
+ for (int i = 0; i < x.Count; i++)
+ {
+ var otherSaved = _other;
+ _other = y[i];
+ if (!x[i].Accept(this))
+ {
+ _other = otherSaved;
+ return false;
+ }
+ _other = otherSaved;
+ }
+ return true;
+ }
+
+ private bool CompareLists(IReadOnlyList x, IReadOnlyList y) where T : JavaNode
+ {
+ if (x.Count != y.Count) return false;
+
+ for (int i = 0; i < x.Count; i++)
+ {
+ var otherSaved = _other;
+ _other = y[i];
+ if (!x[i].Accept(this))
+ {
+ _other = otherSaved;
+ return false;
+ }
+ _other = otherSaved;
+ }
+ return true;
+ }
+
+ public override bool VisitCompilationUnit(CompilationUnit node)
+ {
+ if (_other is not CompilationUnit other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ if (node.Package != null && other.Package != null)
+ {
+ var otherSaved = _other;
+ _other = other.Package;
+ if (!node.Package.Accept(this))
+ {
+ _other = otherSaved;
+ return false;
+ }
+ _other = otherSaved;
+ }
+ else if (node.Package != null || other.Package != null)
+ {
+ return false;
+ }
+
+ return CompareLists(node.Imports, other.Imports) &&
+ CompareLists(node.Types, other.Types);
+ }
+
+ public override bool VisitClassDeclaration(ClassDeclaration node)
+ {
+ if (_other is not ClassDeclaration other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ return node.Name == other.Name &&
+ node.Modifiers == other.Modifiers &&
+ node.IsRecord == other.IsRecord &&
+ CompareAnnotations(node.Annotations, other.Annotations) &&
+ CompareLists(node.TypeParameters, other.TypeParameters) &&
+ CompareLists(node.Interfaces, other.Interfaces) &&
+ CompareLists(node.Members, other.Members);
+ }
+
+ public override bool VisitMethodDeclaration(MethodDeclaration node)
+ {
+ if (_other is not MethodDeclaration other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ return node.Name == other.Name &&
+ node.Modifiers == other.Modifiers &&
+ node.IsConstructor == other.IsConstructor &&
+ CompareAnnotations(node.Annotations, other.Annotations) &&
+ CompareLists(node.TypeParameters, other.TypeParameters) &&
+ CompareLists(node.Parameters, other.Parameters) &&
+ CompareLists(node.Throws, other.Throws);
+ }
+
+ public override bool VisitFieldDeclaration(FieldDeclaration node)
+ {
+ if (_other is not FieldDeclaration other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ return node.Modifiers == other.Modifiers &&
+ CompareAnnotations(node.Annotations, other.Annotations) &&
+ CompareLists(node.Variables, other.Variables);
+ }
+
+ public override bool VisitIdentifierExpression(IdentifierExpression node)
+ {
+ if (_other is not IdentifierExpression other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ return node.Name == other.Name;
+ }
+
+ public override bool VisitLiteralExpression(LiteralExpression node)
+ {
+ if (_other is not LiteralExpression other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ return node.Kind == other.Kind &&
+ Equals(node.Value, other.Value);
+ }
+
+ public override bool VisitBinaryExpression(BinaryExpression node)
+ {
+ if (_other is not BinaryExpression other) return false;
+ if (!CompareLocation(node.Location, other.Location)) return false;
+
+ if (node.Operator != other.Operator) return false;
+
+ var otherSaved = _other;
+ _other = other.Left;
+ if (!node.Left.Accept(this))
+ {
+ _other = otherSaved;
+ return false;
+ }
+
+ _other = other.Right;
+ var result = node.Right.Accept(this);
+ _other = otherSaved;
+ return result;
+ }
+
+ // Additional visit methods would follow the same pattern...
+ }
+
+ ///
+ /// Internal visitor for computing hash codes.
+ ///
+ internal class NodeHasher : JavaVisitorBase
+ {
+ private readonly bool _ignoreLocation;
+ private readonly bool _ignoreJavaDoc;
+ private readonly bool _ignoreAnnotations;
+
+ public NodeHasher(bool ignoreLocation, bool ignoreJavaDoc, bool ignoreAnnotations)
+ {
+ _ignoreLocation = ignoreLocation;
+ _ignoreJavaDoc = ignoreJavaDoc;
+ _ignoreAnnotations = ignoreAnnotations;
+ }
+
+ public int GetHashCode(JavaNode node)
+ {
+ return node.Accept(this);
+ }
+
+ protected override int DefaultVisit(JavaNode node)
+ {
+ return node.GetType().GetHashCode();
+ }
+
+ private int CombineHashCodes(params int[] hashCodes)
+ {
+ unchecked
+ {
+ int hash = 17;
+ foreach (var hashCode in hashCodes)
+ {
+ hash = hash * 31 + hashCode;
+ }
+ return hash;
+ }
+ }
+
+ public override int VisitClassDeclaration(ClassDeclaration node)
+ {
+ return CombineHashCodes(
+ node.GetType().GetHashCode(),
+ node.Name.GetHashCode(),
+ node.Modifiers.GetHashCode(),
+ node.IsRecord.GetHashCode()
+ );
+ }
+
+ public override int VisitMethodDeclaration(MethodDeclaration node)
+ {
+ return CombineHashCodes(
+ node.GetType().GetHashCode(),
+ node.Name.GetHashCode(),
+ node.Modifiers.GetHashCode(),
+ node.IsConstructor.GetHashCode()
+ );
+ }
+
+ public override int VisitIdentifierExpression(IdentifierExpression node)
+ {
+ return CombineHashCodes(
+ node.GetType().GetHashCode(),
+ node.Name.GetHashCode()
+ );
+ }
+
+ public override int VisitLiteralExpression(LiteralExpression node)
+ {
+ return CombineHashCodes(
+ node.GetType().GetHashCode(),
+ node.Kind.GetHashCode(),
+ node.Value?.GetHashCode() ?? 0
+ );
+ }
+ }
+
+ ///
+ /// Computes differences between two AST nodes.
+ ///
+ public class AstDiffer
+ {
+ private readonly AstEqualityComparer _comparer;
+
+ public AstDiffer(bool ignoreLocation = true, bool ignoreJavaDoc = false, bool ignoreAnnotations = false)
+ {
+ _comparer = new AstEqualityComparer(ignoreLocation, ignoreJavaDoc, ignoreAnnotations);
+ }
+
+ public AstDiff ComputeDiff(JavaNode original, JavaNode modified)
+ {
+ var diff = new AstDiff();
+ ComputeDiffRecursive(original, modified, diff);
+ return diff;
+ }
+
+ private void ComputeDiffRecursive(JavaNode? original, JavaNode? modified, AstDiff diff)
+ {
+ if (original == null && modified == null) return;
+
+ if (original == null)
+ {
+ diff.AddAddition(modified!);
+ return;
+ }
+
+ if (modified == null)
+ {
+ diff.AddDeletion(original);
+ return;
+ }
+
+ if (!_comparer.Equals(original, modified))
+ {
+ if (original.GetType() != modified.GetType())
+ {
+ diff.AddDeletion(original);
+ diff.AddAddition(modified);
+ }
+ else
+ {
+ diff.AddModification(original, modified);
+ }
+ }
+
+ // Compare children
+ var originalChildren = original.Children.ToList();
+ var modifiedChildren = modified.Children.ToList();
+
+ // Simple comparison - could be improved with LCS algorithm
+ int minCount = Math.Min(originalChildren.Count, modifiedChildren.Count);
+
+ for (int i = 0; i < minCount; i++)
+ {
+ ComputeDiffRecursive(originalChildren[i], modifiedChildren[i], diff);
+ }
+
+ for (int i = minCount; i < originalChildren.Count; i++)
+ {
+ diff.AddDeletion(originalChildren[i]);
+ }
+
+ for (int i = minCount; i < modifiedChildren.Count; i++)
+ {
+ diff.AddAddition(modifiedChildren[i]);
+ }
+ }
+ }
+
+ ///
+ /// Represents differences between two AST nodes.
+ ///
+ public class AstDiff
+ {
+ private readonly List _entries = new();
+
+ public IReadOnlyList Entries => _entries;
+
+ public IEnumerable Additions => _entries.Where(e => e.Type == DiffType.Added);
+ public IEnumerable Deletions => _entries.Where(e => e.Type == DiffType.Deleted);
+ public IEnumerable Modifications => _entries.Where(e => e.Type == DiffType.Modified);
+
+ internal void AddAddition(JavaNode node)
+ {
+ _entries.Add(new DiffEntry(DiffType.Added, null, node));
+ }
+
+ internal void AddDeletion(JavaNode node)
+ {
+ _entries.Add(new DiffEntry(DiffType.Deleted, node, null));
+ }
+
+ internal void AddModification(JavaNode original, JavaNode modified)
+ {
+ _entries.Add(new DiffEntry(DiffType.Modified, original, modified));
+ }
+
+ public bool IsEmpty => _entries.Count == 0;
+
+ public int TotalChanges => _entries.Count;
+ }
+
+ public class DiffEntry
+ {
+ public DiffType Type { get; }
+ public JavaNode? Original { get; }
+ public JavaNode? Modified { get; }
+
+ public DiffEntry(DiffType type, JavaNode? original, JavaNode? modified)
+ {
+ Type = type;
+ Original = original;
+ Modified = modified;
+ }
+ }
+
+ public enum DiffType
+ {
+ Added,
+ Deleted,
+ Modified
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/JavaNode.cs b/IronJava.Core/AST/JavaNode.cs
new file mode 100644
index 0000000..4226d69
--- /dev/null
+++ b/IronJava.Core/AST/JavaNode.cs
@@ -0,0 +1,62 @@
+using System.Collections.Generic;
+using IronJava.Core.AST.Visitors;
+
+namespace IronJava.Core.AST
+{
+ ///
+ /// Base class for all Java AST nodes.
+ ///
+ public abstract class JavaNode
+ {
+ ///
+ /// The location of this node in the source code.
+ ///
+ public SourceRange Location { get; }
+
+ ///
+ /// Parent node in the AST.
+ ///
+ public JavaNode? Parent { get; internal set; }
+
+ ///
+ /// Child nodes in the AST.
+ ///
+ public IReadOnlyList Children => _children;
+ private readonly List _children = new();
+
+ protected JavaNode(SourceRange location)
+ {
+ Location = location;
+ }
+
+ ///
+ /// Accept a visitor to traverse this node.
+ ///
+ public abstract T Accept(IJavaVisitor visitor);
+
+ ///
+ /// Accept a visitor to traverse this node without returning a value.
+ ///
+ public abstract void Accept(IJavaVisitor visitor);
+
+ ///
+ /// Add a child node.
+ ///
+ protected internal void AddChild(JavaNode child)
+ {
+ _children.Add(child);
+ child.Parent = this;
+ }
+
+ ///
+ /// Add multiple child nodes.
+ ///
+ protected internal void AddChildren(IEnumerable children)
+ {
+ foreach (var child in children)
+ {
+ AddChild(child);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Modifiers.cs b/IronJava.Core/AST/Modifiers.cs
new file mode 100644
index 0000000..f34ae7e
--- /dev/null
+++ b/IronJava.Core/AST/Modifiers.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace IronJava.Core.AST
+{
+ ///
+ /// Java access modifiers and other modifiers as flags.
+ ///
+ [Flags]
+ public enum Modifiers
+ {
+ None = 0,
+ Public = 1 << 0,
+ Protected = 1 << 1,
+ Private = 1 << 2,
+ Static = 1 << 3,
+ Final = 1 << 4,
+ Abstract = 1 << 5,
+ Native = 1 << 6,
+ Synchronized = 1 << 7,
+ Transient = 1 << 8,
+ Volatile = 1 << 9,
+ Strictfp = 1 << 10,
+ Default = 1 << 11,
+ Sealed = 1 << 12,
+ NonSealed = 1 << 13
+ }
+
+ public static class ModifiersExtensions
+ {
+ public static bool IsPublic(this Modifiers modifiers) => (modifiers & Modifiers.Public) != 0;
+ public static bool IsProtected(this Modifiers modifiers) => (modifiers & Modifiers.Protected) != 0;
+ public static bool IsPrivate(this Modifiers modifiers) => (modifiers & Modifiers.Private) != 0;
+ public static bool IsStatic(this Modifiers modifiers) => (modifiers & Modifiers.Static) != 0;
+ public static bool IsFinal(this Modifiers modifiers) => (modifiers & Modifiers.Final) != 0;
+ public static bool IsAbstract(this Modifiers modifiers) => (modifiers & Modifiers.Abstract) != 0;
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Nodes/Annotations.cs b/IronJava.Core/AST/Nodes/Annotations.cs
new file mode 100644
index 0000000..c381e3a
--- /dev/null
+++ b/IronJava.Core/AST/Nodes/Annotations.cs
@@ -0,0 +1,120 @@
+using System.Collections.Generic;
+using IronJava.Core.AST.Visitors;
+
+namespace IronJava.Core.AST.Nodes
+{
+ ///
+ /// Represents a Java annotation usage.
+ ///
+ public class Annotation : JavaNode
+ {
+ public TypeReference Type { get; }
+ public IReadOnlyList Arguments { get; }
+
+ public Annotation(
+ SourceRange location,
+ TypeReference type,
+ IReadOnlyList arguments) : base(location)
+ {
+ Type = type;
+ Arguments = arguments;
+
+ AddChild(type);
+ AddChildren(arguments);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitAnnotation(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitAnnotation(this);
+ }
+
+ ///
+ /// Base class for annotation arguments.
+ ///
+ public abstract class AnnotationArgument : JavaNode
+ {
+ public string? Name { get; }
+
+ protected AnnotationArgument(SourceRange location, string? name) : base(location)
+ {
+ Name = name;
+ }
+ }
+
+ ///
+ /// Represents a simple annotation argument (name = value).
+ ///
+ public class AnnotationValueArgument : AnnotationArgument
+ {
+ public Expression Value { get; }
+
+ public AnnotationValueArgument(
+ SourceRange location,
+ string? name,
+ Expression value) : base(location, name)
+ {
+ Value = value;
+ AddChild(value);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitAnnotationValueArgument(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitAnnotationValueArgument(this);
+ }
+
+ ///
+ /// Represents an array annotation argument.
+ ///
+ public class AnnotationArrayArgument : AnnotationArgument
+ {
+ public IReadOnlyList Values { get; }
+
+ public AnnotationArrayArgument(
+ SourceRange location,
+ string? name,
+ IReadOnlyList values) : base(location, name)
+ {
+ Values = values;
+ AddChildren(values);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitAnnotationArrayArgument(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitAnnotationArrayArgument(this);
+ }
+
+ ///
+ /// Represents JavaDoc documentation.
+ ///
+ public class JavaDoc : JavaNode
+ {
+ public string Content { get; }
+ public IReadOnlyList Tags { get; }
+
+ public JavaDoc(
+ SourceRange location,
+ string content,
+ IReadOnlyList tags) : base(location)
+ {
+ Content = content;
+ Tags = tags;
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitJavaDoc(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitJavaDoc(this);
+ }
+
+ ///
+ /// Represents a JavaDoc tag (@param, @return, etc.).
+ ///
+ public class JavaDocTag
+ {
+ public string Name { get; }
+ public string? Parameter { get; }
+ public string Description { get; }
+
+ public JavaDocTag(string name, string? parameter, string description)
+ {
+ Name = name;
+ Parameter = parameter;
+ Description = description;
+ }
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Nodes/CompilationUnit.cs b/IronJava.Core/AST/Nodes/CompilationUnit.cs
new file mode 100644
index 0000000..5aafccb
--- /dev/null
+++ b/IronJava.Core/AST/Nodes/CompilationUnit.cs
@@ -0,0 +1,79 @@
+using System.Collections.Generic;
+using IronJava.Core.AST.Visitors;
+
+namespace IronJava.Core.AST.Nodes
+{
+ ///
+ /// Represents a Java source file (compilation unit).
+ ///
+ public class CompilationUnit : JavaNode
+ {
+ public PackageDeclaration? Package { get; }
+ public IReadOnlyList Imports { get; }
+ public IReadOnlyList Types { get; }
+
+ public CompilationUnit(
+ SourceRange location,
+ PackageDeclaration? package,
+ IReadOnlyList imports,
+ IReadOnlyList types) : base(location)
+ {
+ Package = package;
+ Imports = imports;
+ Types = types;
+
+ if (package != null) AddChild(package);
+ AddChildren(imports);
+ AddChildren(types);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitCompilationUnit(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitCompilationUnit(this);
+ }
+
+ ///
+ /// Represents a package declaration.
+ ///
+ public class PackageDeclaration : JavaNode
+ {
+ public string PackageName { get; }
+ public IReadOnlyList Annotations { get; }
+
+ public PackageDeclaration(
+ SourceRange location,
+ string packageName,
+ IReadOnlyList annotations) : base(location)
+ {
+ PackageName = packageName;
+ Annotations = annotations;
+ AddChildren(annotations);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitPackageDeclaration(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitPackageDeclaration(this);
+ }
+
+ ///
+ /// Represents an import declaration.
+ ///
+ public class ImportDeclaration : JavaNode
+ {
+ public string ImportPath { get; }
+ public bool IsStatic { get; }
+ public bool IsWildcard { get; }
+
+ public ImportDeclaration(
+ SourceRange location,
+ string importPath,
+ bool isStatic,
+ bool isWildcard) : base(location)
+ {
+ ImportPath = importPath;
+ IsStatic = isStatic;
+ IsWildcard = isWildcard;
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitImportDeclaration(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitImportDeclaration(this);
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Nodes/Expressions.cs b/IronJava.Core/AST/Nodes/Expressions.cs
new file mode 100644
index 0000000..5e2eb35
--- /dev/null
+++ b/IronJava.Core/AST/Nodes/Expressions.cs
@@ -0,0 +1,496 @@
+using System.Collections.Generic;
+using IronJava.Core.AST.Visitors;
+
+namespace IronJava.Core.AST.Nodes
+{
+ ///
+ /// Base class for all expressions.
+ ///
+ public abstract class Expression : JavaNode
+ {
+ protected Expression(SourceRange location) : base(location) { }
+ }
+
+ ///
+ /// Represents a literal value.
+ ///
+ public class LiteralExpression : Expression
+ {
+ public object? Value { get; }
+ public LiteralKind Kind { get; }
+
+ public LiteralExpression(SourceRange location, object? value, LiteralKind kind)
+ : base(location)
+ {
+ Value = value;
+ Kind = kind;
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitLiteralExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitLiteralExpression(this);
+ }
+
+ public enum LiteralKind
+ {
+ Null,
+ Boolean,
+ Integer,
+ Long,
+ Float,
+ Double,
+ Character,
+ String,
+ TextBlock
+ }
+
+ ///
+ /// Represents an identifier reference.
+ ///
+ public class IdentifierExpression : Expression
+ {
+ public string Name { get; }
+
+ public IdentifierExpression(SourceRange location, string name) : base(location)
+ {
+ Name = name;
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitIdentifierExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitIdentifierExpression(this);
+ }
+
+ ///
+ /// Represents 'this' expression.
+ ///
+ public class ThisExpression : Expression
+ {
+ public Expression? Qualifier { get; }
+
+ public ThisExpression(SourceRange location, Expression? qualifier = null) : base(location)
+ {
+ Qualifier = qualifier;
+ if (qualifier != null) AddChild(qualifier);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitThisExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitThisExpression(this);
+ }
+
+ ///
+ /// Represents 'super' expression.
+ ///
+ public class SuperExpression : Expression
+ {
+ public Expression? Qualifier { get; }
+
+ public SuperExpression(SourceRange location, Expression? qualifier = null) : base(location)
+ {
+ Qualifier = qualifier;
+ if (qualifier != null) AddChild(qualifier);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitSuperExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitSuperExpression(this);
+ }
+
+ ///
+ /// Represents a binary expression (a + b, a AND b, etc.).
+ ///
+ public class BinaryExpression : Expression
+ {
+ public Expression Left { get; }
+ public BinaryOperator Operator { get; }
+ public Expression Right { get; }
+
+ public BinaryExpression(
+ SourceRange location,
+ Expression left,
+ BinaryOperator @operator,
+ Expression right) : base(location)
+ {
+ Left = left;
+ Operator = @operator;
+ Right = right;
+
+ AddChild(left);
+ AddChild(right);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitBinaryExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitBinaryExpression(this);
+ }
+
+ public enum BinaryOperator
+ {
+ // Arithmetic
+ Add, Subtract, Multiply, Divide, Modulo,
+ // Bitwise
+ BitwiseAnd, BitwiseOr, BitwiseXor, LeftShift, RightShift, UnsignedRightShift,
+ // Logical
+ LogicalAnd, LogicalOr,
+ // Comparison
+ Equals, NotEquals, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual,
+ // Assignment
+ Assign, AddAssign, SubtractAssign, MultiplyAssign, DivideAssign, ModuloAssign,
+ BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign,
+ LeftShiftAssign, RightShiftAssign, UnsignedRightShiftAssign
+ }
+
+ ///
+ /// Represents a unary expression (!a, ++i, etc.).
+ ///
+ public class UnaryExpression : Expression
+ {
+ public UnaryOperator Operator { get; }
+ public Expression Operand { get; }
+ public bool IsPrefix { get; }
+
+ public UnaryExpression(
+ SourceRange location,
+ UnaryOperator @operator,
+ Expression operand,
+ bool isPrefix = true) : base(location)
+ {
+ Operator = @operator;
+ Operand = operand;
+ IsPrefix = isPrefix;
+
+ AddChild(operand);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitUnaryExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitUnaryExpression(this);
+ }
+
+ public enum UnaryOperator
+ {
+ Plus, Minus, BitwiseNot, LogicalNot,
+ PreIncrement, PreDecrement, PostIncrement, PostDecrement
+ }
+
+ ///
+ /// Represents a conditional expression (a ? b : c).
+ ///
+ public class ConditionalExpression : Expression
+ {
+ public Expression Condition { get; }
+ public Expression ThenExpression { get; }
+ public Expression ElseExpression { get; }
+
+ public ConditionalExpression(
+ SourceRange location,
+ Expression condition,
+ Expression thenExpression,
+ Expression elseExpression) : base(location)
+ {
+ Condition = condition;
+ ThenExpression = thenExpression;
+ ElseExpression = elseExpression;
+
+ AddChild(condition);
+ AddChild(thenExpression);
+ AddChild(elseExpression);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitConditionalExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitConditionalExpression(this);
+ }
+
+ ///
+ /// Represents a method call expression.
+ ///
+ public class MethodCallExpression : Expression
+ {
+ public Expression? Target { get; }
+ public string MethodName { get; }
+ public IReadOnlyList TypeArguments { get; }
+ public IReadOnlyList Arguments { get; }
+
+ public MethodCallExpression(
+ SourceRange location,
+ Expression? target,
+ string methodName,
+ IReadOnlyList typeArguments,
+ IReadOnlyList arguments) : base(location)
+ {
+ Target = target;
+ MethodName = methodName;
+ TypeArguments = typeArguments;
+ Arguments = arguments;
+
+ if (target != null) AddChild(target);
+ AddChildren(typeArguments);
+ AddChildren(arguments);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitMethodCallExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitMethodCallExpression(this);
+ }
+
+ ///
+ /// Represents a field access expression.
+ ///
+ public class FieldAccessExpression : Expression
+ {
+ public Expression Target { get; }
+ public string FieldName { get; }
+
+ public FieldAccessExpression(
+ SourceRange location,
+ Expression target,
+ string fieldName) : base(location)
+ {
+ Target = target;
+ FieldName = fieldName;
+
+ AddChild(target);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitFieldAccessExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitFieldAccessExpression(this);
+ }
+
+ ///
+ /// Represents an array access expression.
+ ///
+ public class ArrayAccessExpression : Expression
+ {
+ public Expression Array { get; }
+ public Expression Index { get; }
+
+ public ArrayAccessExpression(
+ SourceRange location,
+ Expression array,
+ Expression index) : base(location)
+ {
+ Array = array;
+ Index = index;
+
+ AddChild(array);
+ AddChild(index);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitArrayAccessExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitArrayAccessExpression(this);
+ }
+
+ ///
+ /// Represents a cast expression.
+ ///
+ public class CastExpression : Expression
+ {
+ public TypeReference Type { get; }
+ public Expression Expression { get; }
+
+ public CastExpression(
+ SourceRange location,
+ TypeReference type,
+ Expression expression) : base(location)
+ {
+ Type = type;
+ Expression = expression;
+
+ AddChild(type);
+ AddChild(expression);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitCastExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitCastExpression(this);
+ }
+
+ ///
+ /// Represents an instanceof expression.
+ ///
+ public class InstanceOfExpression : Expression
+ {
+ public Expression Expression { get; }
+ public TypeReference Type { get; }
+ public string? PatternVariable { get; }
+
+ public InstanceOfExpression(
+ SourceRange location,
+ Expression expression,
+ TypeReference type,
+ string? patternVariable = null) : base(location)
+ {
+ Expression = expression;
+ Type = type;
+ PatternVariable = patternVariable;
+
+ AddChild(expression);
+ AddChild(type);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitInstanceOfExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitInstanceOfExpression(this);
+ }
+
+ ///
+ /// Represents a 'new' expression for object creation.
+ ///
+ public class NewExpression : Expression
+ {
+ public ClassOrInterfaceType Type { get; }
+ public IReadOnlyList Arguments { get; }
+ public ClassDeclaration? AnonymousClassBody { get; }
+
+ public NewExpression(
+ SourceRange location,
+ ClassOrInterfaceType type,
+ IReadOnlyList arguments,
+ ClassDeclaration? anonymousClassBody = null) : base(location)
+ {
+ Type = type;
+ Arguments = arguments;
+ AnonymousClassBody = anonymousClassBody;
+
+ AddChild(type);
+ AddChildren(arguments);
+ if (anonymousClassBody != null) AddChild(anonymousClassBody);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitNewExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitNewExpression(this);
+ }
+
+ ///
+ /// Represents an array creation expression.
+ ///
+ public class NewArrayExpression : Expression
+ {
+ public TypeReference ElementType { get; }
+ public IReadOnlyList Dimensions { get; }
+ public ArrayInitializer? Initializer { get; }
+
+ public NewArrayExpression(
+ SourceRange location,
+ TypeReference elementType,
+ IReadOnlyList dimensions,
+ ArrayInitializer? initializer = null) : base(location)
+ {
+ ElementType = elementType;
+ Dimensions = dimensions;
+ Initializer = initializer;
+
+ AddChild(elementType);
+ AddChildren(dimensions);
+ if (initializer != null) AddChild(initializer);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitNewArrayExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitNewArrayExpression(this);
+ }
+
+ ///
+ /// Represents an array initializer.
+ ///
+ public class ArrayInitializer : Expression
+ {
+ public IReadOnlyList Elements { get; }
+
+ public ArrayInitializer(
+ SourceRange location,
+ IReadOnlyList elements) : base(location)
+ {
+ Elements = elements;
+ AddChildren(elements);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitArrayInitializer(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitArrayInitializer(this);
+ }
+
+ ///
+ /// Represents a lambda expression.
+ ///
+ public class LambdaExpression : Expression
+ {
+ public IReadOnlyList Parameters { get; }
+ public JavaNode Body { get; } // Can be Expression or BlockStatement
+
+ public LambdaExpression(
+ SourceRange location,
+ IReadOnlyList parameters,
+ JavaNode body) : base(location)
+ {
+ Parameters = parameters;
+ Body = body;
+
+ AddChildren(parameters);
+ AddChild(body);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitLambdaExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitLambdaExpression(this);
+ }
+
+ ///
+ /// Represents a lambda parameter.
+ ///
+ public class LambdaParameter : JavaNode
+ {
+ public string Name { get; }
+ public TypeReference? Type { get; }
+ public bool IsFinal { get; }
+
+ public LambdaParameter(
+ SourceRange location,
+ string name,
+ TypeReference? type = null,
+ bool isFinal = false) : base(location)
+ {
+ Name = name;
+ Type = type;
+ IsFinal = isFinal;
+
+ if (type != null) AddChild(type);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitLambdaParameter(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitLambdaParameter(this);
+ }
+
+ ///
+ /// Represents a method reference expression (String::length).
+ ///
+ public class MethodReferenceExpression : Expression
+ {
+ public Expression Target { get; }
+ public string MethodName { get; }
+ public IReadOnlyList TypeArguments { get; }
+
+ public MethodReferenceExpression(
+ SourceRange location,
+ Expression target,
+ string methodName,
+ IReadOnlyList typeArguments) : base(location)
+ {
+ Target = target;
+ MethodName = methodName;
+ TypeArguments = typeArguments;
+
+ AddChild(target);
+ AddChildren(typeArguments);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitMethodReferenceExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitMethodReferenceExpression(this);
+ }
+
+ ///
+ /// Represents a class literal expression (String.class).
+ ///
+ public class ClassLiteralExpression : Expression
+ {
+ public TypeReference Type { get; }
+
+ public ClassLiteralExpression(SourceRange location, TypeReference type) : base(location)
+ {
+ Type = type;
+ AddChild(type);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitClassLiteralExpression(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitClassLiteralExpression(this);
+ }
+}
\ No newline at end of file
diff --git a/IronJava.Core/AST/Nodes/MemberDeclarations.cs b/IronJava.Core/AST/Nodes/MemberDeclarations.cs
new file mode 100644
index 0000000..ce19806
--- /dev/null
+++ b/IronJava.Core/AST/Nodes/MemberDeclarations.cs
@@ -0,0 +1,243 @@
+using System.Collections.Generic;
+using IronJava.Core.AST.Visitors;
+
+namespace IronJava.Core.AST.Nodes
+{
+ ///
+ /// Base class for class/interface members.
+ ///
+ public abstract class MemberDeclaration : JavaNode
+ {
+ public Modifiers Modifiers { get; }
+ public IReadOnlyList Annotations { get; }
+ public JavaDoc? JavaDoc { get; }
+
+ protected MemberDeclaration(
+ SourceRange location,
+ Modifiers modifiers,
+ IReadOnlyList annotations,
+ JavaDoc? javaDoc) : base(location)
+ {
+ Modifiers = modifiers;
+ Annotations = annotations;
+ JavaDoc = javaDoc;
+
+ AddChildren(annotations);
+ if (javaDoc != null) AddChild(javaDoc);
+ }
+ }
+
+ ///
+ /// Represents a field declaration.
+ ///
+ public class FieldDeclaration : MemberDeclaration
+ {
+ public TypeReference Type { get; }
+ public IReadOnlyList Variables { get; }
+
+ public FieldDeclaration(
+ SourceRange location,
+ Modifiers modifiers,
+ IReadOnlyList annotations,
+ TypeReference type,
+ IReadOnlyList variables,
+ JavaDoc? javaDoc)
+ : base(location, modifiers, annotations, javaDoc)
+ {
+ Type = type;
+ Variables = variables;
+
+ AddChild(type);
+ AddChildren(variables);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitFieldDeclaration(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitFieldDeclaration(this);
+ }
+
+ ///
+ /// Represents a method declaration.
+ ///
+ public class MethodDeclaration : MemberDeclaration
+ {
+ public string Name { get; }
+ public TypeReference? ReturnType { get; } // null for constructors
+ public IReadOnlyList TypeParameters { get; }
+ public IReadOnlyList Parameters { get; }
+ public IReadOnlyList Throws { get; }
+ public BlockStatement? Body { get; }
+ public bool IsConstructor { get; }
+
+ public MethodDeclaration(
+ SourceRange location,
+ string name,
+ Modifiers modifiers,
+ IReadOnlyList annotations,
+ TypeReference? returnType,
+ IReadOnlyList typeParameters,
+ IReadOnlyList parameters,
+ IReadOnlyList throws,
+ BlockStatement? body,
+ JavaDoc? javaDoc,
+ bool isConstructor = false)
+ : base(location, modifiers, annotations, javaDoc)
+ {
+ Name = name;
+ ReturnType = returnType;
+ TypeParameters = typeParameters;
+ Parameters = parameters;
+ Throws = throws;
+ Body = body;
+ IsConstructor = isConstructor;
+
+ if (returnType != null) AddChild(returnType);
+ AddChildren(typeParameters);
+ AddChildren(parameters);
+ AddChildren(throws);
+ if (body != null) AddChild(body);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitMethodDeclaration(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitMethodDeclaration(this);
+ }
+
+ ///
+ /// Represents an initializer block (static or instance).
+ ///
+ public class InitializerBlock : MemberDeclaration
+ {
+ public BlockStatement Body { get; }
+ public bool IsStatic { get; }
+
+ public InitializerBlock(
+ SourceRange location,
+ BlockStatement body,
+ bool isStatic)
+ : base(location, isStatic ? Modifiers.Static : Modifiers.None, new List(), null)
+ {
+ Body = body;
+ IsStatic = isStatic;
+ AddChild(body);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitInitializerBlock(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitInitializerBlock(this);
+ }
+
+ ///
+ /// Represents a variable declarator (used in fields and local variables).
+ ///
+ public class VariableDeclarator : JavaNode
+ {
+ public string Name { get; }
+ public int ArrayDimensions { get; }
+ public Expression? Initializer { get; }
+
+ public VariableDeclarator(
+ SourceRange location,
+ string name,
+ int arrayDimensions,
+ Expression? initializer) : base(location)
+ {
+ Name = name;
+ ArrayDimensions = arrayDimensions;
+ Initializer = initializer;
+
+ if (initializer != null) AddChild(initializer);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitVariableDeclarator(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitVariableDeclarator(this);
+ }
+
+ ///
+ /// Represents a method parameter.
+ ///
+ public class Parameter : JavaNode
+ {
+ public TypeReference Type { get; }
+ public string Name { get; }
+ public bool IsVarArgs { get; }
+ public bool IsFinal { get; }
+ public IReadOnlyList Annotations { get; }
+
+ public Parameter(
+ SourceRange location,
+ TypeReference type,
+ string name,
+ bool isVarArgs,
+ bool isFinal,
+ IReadOnlyList annotations) : base(location)
+ {
+ Type = type;
+ Name = name;
+ IsVarArgs = isVarArgs;
+ IsFinal = isFinal;
+ Annotations = annotations;
+
+ AddChild(type);
+ AddChildren(annotations);
+ }
+
+ public override T Accept(IJavaVisitor visitor) => visitor.VisitParameter(this);
+ public override void Accept(IJavaVisitor visitor) => visitor.VisitParameter(this);
+ }
+
+ ///
+ /// Represents an enum constant.
+ ///
+ public class EnumConstant : JavaNode
+ {
+ public string Name { get; }
+ public IReadOnlyList Annotations { get; }
+ public IReadOnlyList Arguments { get; }
+ public ClassDeclaration? Body { get; }
+
+ public EnumConstant(
+ SourceRange location,
+ string name,
+ IReadOnlyList annotations,
+ IReadOnlyList