Skip to content

Latest commit

 

History

History
122 lines (85 loc) · 4.27 KB

File metadata and controls

122 lines (85 loc) · 4.27 KB

Contributing to Rusty-JavaC

Rusty-JavaC is an early-stage Java compiler written in Rust. Treat every change as compiler work: keep it small, test the generated class files, and leave the code easier to understand than you found it.

Setup

Required tools:

  • Rust 1.85+ with Cargo
  • Java 21+ for javac, javap, and JVM verification
  • Git

Build and run the Rust tests:

cargo build --locked
cargo test --locked

For bytecode, lowering, or type changes, also compile at least one Java fixture and inspect the generated class:

cargo run --locked --example compiler-example -- --output-dir target/test-output tests/java/HelloWorld.java
javap -v -c target/test-output/HelloWorld.class
java -Xverify:all -cp target/test-output HelloWorld

Project Layout

The project is a single Cargo package. Compiler stages are regular Rust modules under src/:

src/
|- ast           # Syntax node wrappers over the parsed tree
|- lexer         # Tokenization and Unicode escape handling
|- parser        # Recursive-descent parser
|- hir           # High-level IR, lowering, and expression inference
|- ty            # Java type model, descriptors, and assignability
|- call_resolver # Class catalog and method/constructor lookup
|- bytecode      # JVM bytecode generation and bytecode validation
|- classfile     # .class reading and writing helpers
|- diagnostics   # User-facing diagnostic rendering
`- compiler      # Classpath, incremental state, and compile pipeline

The compile path is:

Java source
  -> lexer
  -> parser
  -> ast
  -> hir lowering
  -> type and call resolution
  -> bytecode generation
  -> classfile writer

src/lib.rs should stay small. Add new implementation inside the stage that owns it, then expose only the API that other stages need.

Change Guidelines

Keep compiler behavior and structure separate:

  • Parser code should describe syntax, not Java semantics.
  • Lowering should translate syntax into HIR and preserve useful source spans.
  • Type inference and call resolution should avoid hardcoded one-off cases when the class catalog can answer the question.
  • Bytecode generation should consume typed/resolved HIR instead of re-parsing syntax decisions.
  • Diagnostics should report the real source span and explain the fix when the compiler knows one.

Prefer small modules with clear ownership. If a file grows because it handles several independent concepts, split by concept rather than by arbitrary line count.

Do not add tests that only assert exact pretty-printed diagnostic text unless the output is intentionally stable. Prefer Java fixtures, JVM verification, javap inspection, or snapshot tests for rendered diagnostics.

Java Fixtures

Put integration fixtures under tests/java/. A good fixture:

  • compiles with javac
  • exercises one compiler capability or one known edge case
  • can be verified with java -Xverify:all when it has a runnable main
  • avoids unrelated language features that make failures harder to diagnose

When changing bytecode output, compare against javac when practical. Exact bytecode does not need to match, but verifier behavior and runtime behavior should.

Checklist Before Commit

Run the narrowest useful checks first, then the full set before committing:

cargo fmt --all
cargo check --workspace --all-targets --locked
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo test --workspace --locked

For compiler changes, also compile the affected fixtures:

cargo run --locked --example compiler-example -- --output-dir target/java-fixtures-rusty tests/java/HelloWorld.java
javap -v -c target/java-fixtures-rusty/HelloWorld.class

Commits

Use Conventional Commits:

type(scope): short description

Common types are feat, fix, refactor, docs, test, ci, and chore. Useful scopes are module names such as parser, hir, bytecode, compiler, diagnostics, and classfile.

Keep commits focused. If a feature needs parser, lowering, bytecode, and tests, split it into reviewable commits when possible.

Roadmap

Use TODO.md as the working backlog. If a PR finishes an item, update the checkbox in the same PR.

License

By contributing, you agree that your contributions are licensed under the MIT License.