# Kotlin Grammar Smoke Build

This is the source-only path for building Rust modules from the ANTLR Kotlin
grammar.

## Inputs

- Kotlin grammar from `antlr/grammars-v4`, directory `kotlin/kotlin`.
- Keep the checkout and generated scratch files under the repository's ignored
  `target/antlr-cleanroom/`; `cargo clean` removes them.

## Generate Rust Modules

```bash
GRAMMAR=target/antlr-cleanroom/grammars-v4/kotlin/kotlin

cargo run -p antlr-rust-codegen --bin antlr4-rust-gen -- \
  "$GRAMMAR/KotlinLexer.g4" \
  "$GRAMMAR/KotlinParser.g4" \
  --lib "$GRAMMAR" \
  --require-generated-parser \
  --out-dir target/antlr-cleanroom/kotlin-rust
```

`UnicodeClasses.g4` is resolved through `--lib`; it does not need to be listed
as another root.

This emits:

- `kotlin_lexer.rs`
- `kotlin_parser.rs`

The generated lexer caches its deserialized lexer ATN with `OnceLock`. The
generated parser embeds a versioned packed parser ATN, validates it once without
rebuilding an object graph, and delegates recognition to `antlr4_runtime`.

## Choose the Kotlin Entry Rule

`antlr4-rust-gen` emits one public parser method for every grammar rule and
lists those methods in the generated parser rustdoc. Choose the method that
matches the Kotlin input shape rather than assuming the first rule is always
right:

- `.kt` compilation units use `parser.kotlin_file()`.
- `.kts` script-style input uses `parser.script()`.

ANTLR recovery can produce a parse tree even when the wrong entry rule is used,
but the tree will contain recovered error nodes and diagnostics. When adding a
new Kotlin input form, confirm the entry rule against the upstream grammar and
check parser diagnostics.

## Smoke Crate

Create any Rust crate that depends on this runtime:

```toml
[dependencies]
antlr-rust-runtime = { path = "../path/to/runtime-crate" }
```

Replace the path with the relative path from the smoke crate to this checkout.

Then include the generated modules and parse a Kotlin sample:

```rust
use generated::kotlin_lexer::KotlinLexer;
use generated::kotlin_parser::{self, KotlinParser};

let tree = kotlin_parser::parse("fun main() {}", KotlinLexer::new, KotlinParser::kotlin_file)
    .expect("entry rule parses");
assert!(tree.text().contains("fun"));
```

Use `parse_with_parser` when a caller also needs parser state after the entry
rule, such as syntax diagnostics or the token stream:

```rust
use antlr4_runtime::Parser;
use generated::kotlin_lexer::KotlinLexer;
use generated::kotlin_parser::{self, KotlinParser};

let output =
    kotlin_parser::parse_with_parser("fun main() {}", KotlinLexer::new, KotlinParser::kotlin_file)
        .expect("entry rule parses");
let syntax_errors = output.parser.number_of_syntax_errors();
let tree = output.result;
let tokens = output.parser.into_token_stream();

assert_eq!(syntax_errors, 0);
assert!(tree.text().contains("fun"));
assert!(!tokens.tokens().is_empty());
```

Use `parse_stream` to parse directly from a Rust reader while retaining the
input's source name:

```rust
use std::fs::File;
use antlr4_runtime::InputStream;
use generated::kotlin_lexer::KotlinLexer;
use generated::kotlin_parser::{self, KotlinParser};

let path = std::path::Path::new("Main.kt");
let input = InputStream::from_reader_with_source_name(
    File::open(path).expect("Kotlin source should open"),
    path.display().to_string(),
)
.expect("Kotlin source should be UTF-8");
let parsed = kotlin_parser::parse_stream(input, KotlinLexer::new, KotlinParser::kotlin_file)
    .expect("entry rule parses");
assert!(parsed.tree().text().contains("fun"));
```

`InputStream::from_reader` also accepts stdin, sockets, cursors, and other
`std::io::Read` implementations when no explicit source name is needed.

The generated helpers are additive. The explicit path remains available when
the caller needs to adjust parser options or attach custom error handling before
the entry rule:

```rust
use antlr4_runtime::{CommonTokenStream, InputStream};
use generated::kotlin_lexer::KotlinLexer;
use generated::kotlin_parser::KotlinParser;

let lexer = KotlinLexer::new(InputStream::new("fun main() {}"));
let tokens = CommonTokenStream::new(lexer);
let mut parser = KotlinParser::new(tokens);
let tree = parser.kotlin_file().expect("entry rule parses");
assert!(tree.text().contains("fun"));
```

Validated locally: the generated Kotlin lexer emits real tokens and the generated parser recognizes the `parser.kotlin_file()` entry rule for
`fun main() {}`.
