{"id":10502,"library":"antlr4ng","title":"ANTLR4 TypeScript Runtime (antlr4ng)","description":"antlr4ng is an alternative, TypeScript-first runtime for ANTLR4 grammars, specifically designed to be used with the `antlr-ng` parser generation tool. Currently stable at version `3.0.16`, it receives frequent point releases addressing bugs and introducing minor enhancements. Unlike the original ANTLR4 JavaScript runtime, `antlr4ng` operates identically across Node.js and browser environments and is built with strict TypeScript nullability checks. It requires an ES2022 (ES6) compatible runtime for features like static initialization blocks and private class fields. While implementing nearly all features of the Java ANTLR4 runtime, it notably omits the `UnbufferedCharStream` class. Developers migrating from other ANTLR4 JavaScript runtimes will need to adjust code for stricter null handling and renamed internal members.","status":"active","version":"3.0.16","language":"javascript","source_language":"en","source_url":"https://github.com/mike-lischke/antlr4ng","tags":["javascript","lexer","parser","antlr","antlr4","grammar","TypeScript","typescript"],"install":[{"cmd":"npm install antlr4ng","lang":"bash","label":"npm"},{"cmd":"yarn add antlr4ng","lang":"bash","label":"yarn"},{"cmd":"pnpm add antlr4ng","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The `antlr4ng` package is an ES Module (ESM) and requires an `import` statement. It mandates ES2022+ features for its internal implementation.","wrong":"const { CharStream } = require(\"antlr4ng\");","symbol":"CharStream","correct":"import { CharStream } from \"antlr4ng\";"},{"note":"Part of the core `antlr4ng` runtime for managing tokens from a lexer, typically used in conjunction with a `CharStream`.","wrong":"const { CommonTokenStream } = require(\"antlr4ng\");","symbol":"CommonTokenStream","correct":"import { CommonTokenStream } from \"antlr4ng\";"},{"note":"Lexer, parser, and visitor classes are generated by the `antlr-ng` tool into user-defined paths. When using Node.js with ESM, the `.js` extension must be explicitly included in the import path.","wrong":"import { ExpressionLexer } from \"antlr4ng\";\nimport { ExpressionLexer } from \"./generated/ExpressionLexer\";","symbol":"ExpressionLexer","correct":"import { ExpressionLexer } from \"./generated/ExpressionLexer.js\";"},{"note":"The base class for generated parsers, often extended for custom logic. It follows ESM import rules and ES2022+ requirements.","wrong":"const { Parser } = require(\"antlr4ng\");","symbol":"Parser","correct":"import { Parser } from \"antlr4ng\";"}],"quickstart":{"code":"import { CharStream, CommonTokenStream } from \"antlr4ng\";\nimport { ExpressionLexer } from \"./generated/ExpressionLexer.js\";\nimport { ExpressionParser } from \"./generated/ExpressionParser.js\";\n\nconst input = \"1 + 2 * 3\";\nconst inputStream = CharStream.fromString(input);\nconst lexer = new ExpressionLexer(inputStream);\nconst tokenStream = new CommonTokenStream(lexer);\nconst parser = new ExpressionParser(tokenStream);\n\n// Optionally configure error handling or listeners\n// parser.removeErrorListeners();\n// parser.addErrorListener(new MyErrorListener());\n\nconst tree = parser.start();\n\n// To demonstrate visitor usage (assuming MyVisitor is defined):\n// import { ExpressionVisitor } from \"./generated/ExpressionVisitor.js\";\n// import { AddContext } from \"./generated/ExpressionParser.js\"; // Example context type\n//\n// class MyVisitor extends ExpressionVisitor<number> {\n//   public visitAdd = (ctx: AddContext): number => {\n//     // Assuming visit is implemented for other rule contexts\n//     return this.visit(ctx.expression(0)) + this.visit(ctx.expression(1));\n//   };\n//   // ... implement other visit methods\n//   protected defaultResult(): number { return 0; }\n//   protected aggregateResult(aggregate: number, nextResult: number): number { return nextResult; }\n// }\n// const result = new MyVisitor().visit(tree);\n// console.log(`Parse tree successfully created. Visitor result: ${result}`);\nconsole.log(\"Parse tree successfully created.\");\n","lang":"typescript","description":"Demonstrates parsing a simple arithmetic expression using generated lexer and parser, highlighting basic setup with `CharStream` and `CommonTokenStream` from `antlr4ng`."},"warnings":[{"fix":"Ensure your Node.js version is 16.x or higher, or configure your bundler/TypeScript compiler to target `ES2022` or higher.","message":"The `antlr4ng` runtime requires ES2022 (ES13) or newer JavaScript environments, utilizing features like static initialization blocks and private class fields (`#field`). Older JavaScript runtimes (e.g., Node.js < 16) will fail.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Implement explicit null checks (`if (member !== null)`) or use TypeScript's non-null assertion operator (`member!`) where appropriate, prioritizing safety.","message":"Migration from other ANTLR4 JavaScript runtimes requires adjusting code due to `antlr4ng`'s stricter TypeScript nullability. Many previously implicitly nullable members are now explicitly typed as nullable, aligning with Java runtime behavior.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Update references to these renamed members throughout your custom parser logic, error handlers, or visitor/listener implementations.","message":"Several internal parser and recognizer member variables have been renamed for consistency with TypeScript conventions (e.g., `_ctx` to `context`, `_errHandler` to `errorHandler`, `_input` to `inputStream`, `_interp` to `interpreter`).","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Always use the `antlr-ng` tool to generate your lexer and parser files for optimal compatibility with the `antlr4ng` runtime.","message":"This `antlr4ng` runtime is designed to be used with parsers generated by the `antlr-ng` tool. While it implements ANTLR4, direct compatibility with parsers generated by the original ANTLR4 JavaScript target might not be guaranteed due to numerous bug fixes and internal changes.","severity":"gotcha","affected_versions":">=3.0.0"},{"fix":"Change `import { MyLexer } from './MyLexer';` to `import { MyLexer } from './MyLexer.js';` for generated files.","message":"When importing generated lexer/parser/visitor files in an ESM Node.js environment, the `.js` extension must be explicitly included in the import path, even if the source file is `.ts`.","severity":"gotcha","affected_versions":">=3.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Replace `parser._ctx` with `parser.context`. Similarly, change `_errHandler` to `errorHandler`, `_input` to `inputStream`, and `_interp` to `interpreter`.","cause":"Accessing an old, renamed internal member of `Parser` or `Recognizer`.","error":"TS2339: Property '_ctx' does not exist on type 'Parser'. Did you mean 'context'?"},{"fix":"Ensure your project is configured for ES Modules and use `import { CharStream } from 'antlr4ng';` instead of `const { CharStream } = require('antlr4ng');`.","cause":"Attempting to use `require()` for the `antlr4ng` package, which is an ESM-only library and relies on ES2022+ features, or incorrect CJS interop.","error":"TypeError: Class constructor CharStream cannot be invoked without 'new'"},{"fix":"Verify the relative path to your `generated` folder. For ESM in Node.js, ensure the import statement includes the `.js` extension: `import { ExpressionLexer } from './generated/ExpressionLexer.js';`","cause":"The import path for generated files is incorrect, or the `.js` extension is missing when running in an ESM Node.js environment.","error":"Error: Cannot find module './generated/ExpressionLexer'"},{"fix":"Upgrade your Node.js runtime to version 16.x or newer, or ensure your build tools (e.g., Babel, TypeScript compiler) are configured to transpile to a target that supports ES2022 or higher.","cause":"Running `antlr4ng` in a JavaScript environment that does not support ES2022 (ES13) features, specifically private class fields (`#field`).","error":"SyntaxError: Private field '#field' must be declared in an enclosing class"}],"ecosystem":"npm"}