Kotlin Grammar Smoke Build
August 3, 2026 ยท View on GitHub
This is the source-only path for building Rust modules from the ANTLR Kotlin grammar.
Inputs
- Kotlin grammar from
antlr/grammars-v4, directorykotlin/kotlin. - Keep the checkout and generated scratch files under the repository's ignored
target/antlr-cleanroom/;cargo cleanremoves them.
Generate Rust Modules
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.rskotlin_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:
.ktcompilation units useparser.kotlin_file()..ktsscript-style input usesparser.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:
[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:
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:
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:
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:
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() {}.