TypeScript / WASM
Hyperlark ships as a WebAssembly module with a typed TypeScript interface. It runs
on Node ≥ 22 (the default entry), and in the browser, bundlers, Deno, Bun and
edge runtimes (the @hyperlark/hyperlark/web entry).
You write a grammar in Lark’s .lark
language and get a parse tree, or a value computed by a
transformer.
Install
Section titled “Install”npm install @hyperlark/hyperlark@betaHyperlark is in beta, hence the @beta tag.
Your first parser
Section titled “Your first parser”import { Lark, pretty } from "@hyperlark/hyperlark";
const parser = new Lark(String.raw` start: "hello" NAME NAME: /\w+/ %ignore " "`);
const tree = parser.parse("hello world");console.log(pretty(tree));start worldstart is a rule, NAME a terminal. Terminals define the alphabet of your
language, while rules define its structure; terminals are written in
UPPER-CASE, rules in lower-case. %ignore " " tells the parser to ignore
spaces. The literal "hello" is matched, but filtered out of the tree as
punctuation.
String.raw keeps the backslash in \w; a plain template literal drops it.
parse returns Node, which is Tree | Token | null; narrow it with
isTree before reading children (Working with trees).
Choosing a parser
Section titled “Choosing a parser”The sample uses the default, Earley, which accepts any context-free grammar, even ambiguous ones. LALR is much
faster, with some grammar restrictions; we recommend starting with it: pass
{ parser: "lalr" } as the second argument. Only LALR can compute a value
during the parse, recover from errors,
parse interactively, or stream subtrees with
parseStream.
How it works compares the two.
Errors
Section titled “Errors”A failed parse throws a subclass of UnexpectedInput.
Errors lists them and shows how to catch them.
Browsers and other runtimes
Section titled “Browsers and other runtimes”Everywhere but Node, import the /web entry and await init() once, before
the first parse:
import init, { pretty } from "@hyperlark/hyperlark/web";
const { Lark } = await init();
const parser = new Lark(String.raw` start: "hello" NAME NAME: /\w+/ %ignore " "`);
console.log(pretty(parser.parse("hello world")));init() returns Lark, BasicLexer, LarkError and its subclasses, and
the other WASM classes, under the Node entry’s names.
Helpers that need no WASM, such as pretty and Transformer, stay named
imports.
With no argument, init() fetches hyperlark_wasm_bg.wasm relative to the
module’s URL. To load it from elsewhere, pass a URL, a Response, the bytes
or a compiled WebAssembly.Module. The file is 2 MB, 740 KB gzipped.
Importing grammar files
Section titled “Importing grammar files”%import common.NUMBER and the rest of the built-in library need no setup.
To import your own .lark files, pass a loader in the import_loader
option: mapLoader(sources) for text in memory, fsLoader(rootDir) on Node
(Directives).
Precompiled grammars
Section titled “Precompiled grammars”A compiled LALR grammar can be saved as JSON and loaded later, instead of
compiling again. The npm package loads one but cannot save it: save from
Rust or Python, then call Lark.fromJSON(json). The Node-only
@hyperlark/hyperlark/slim entry has no grammar compiler and a smaller WASM
module, so it loads saved grammars only. See
Saving a compiled grammar.
Next steps
Section titled “Next steps”- Examples: four TypeScript and JavaScript programs, including a calculator and interactive parsing.
- Transformers: turn a tree into a value, or compute it during the parse.
- Working with trees: queries, walking, positions.
- Errors: catch a failed parse and show where.
- Grammar reference: the
.larklanguage. - Feature matrix: what each target supports.
- Alternatives: compared with chevrotain, peggy, nearley, ohm and tree-sitter.
- API reference: TypeDoc for the package.