### Configuring and Using Dialects
Source: https://context7.com/lezer-parser/lr/llms.txt
Configure a parser to use a specific dialect. This example shows how to create a parser with the 'jsx' dialect enabled.
```typescript
import { parser } from "./javascript-parser"
const jsxParser = parser.configure({ dialect: "jsx" })
const tree = jsxParser.parse("
hello
")
```
--------------------------------
### Controlled Incremental Advance with PartialParse
Source: https://context7.com/lezer-parser/lr/llms.txt
Use `startParse` to get a `PartialParse` object and `advance()` to drive parsing step-by-step. `stopAt(pos)` limits parsing to a specific position, useful for viewport-based updates. The loop yields to the UI if parsing exceeds a budget.
```typescript
import { parser } from "./generated-parser"
import { TreeFragment } from "@lezer/common"
const largeDoc = "/* 100k characters of code */"
const partial = parser.startParse(largeDoc, [], [{ from: 0, to: largeDoc.length }])
// Only parse the first 5000 characters for now (e.g., visible viewport)
partial.stopAt(5000)
let tree = null
const BUDGET_MS = 16 // one frame
const deadline = Date.now() + BUDGET_MS
while (!tree) {
tree = partial.advance()
if (Date.now() > deadline) break // yield to UI, resume next frame
}
if (tree) {
console.log("Fully parsed up to stopAt:", tree.length)
} else {
// Can inspect partial.parsedPos to know how far we've gotten
console.log("Parsed so far:", partial.parsedPos)
}
```
--------------------------------
### External Tokenizer with `Stack.context`
Source: https://context7.com/lezer-parser/lr/llms.txt
Access grammar context using `Stack.context` to make tokenizer decisions. This example emits the 'in' keyword only when inside a for-header.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { identifier, kwIn } from "./my-grammar.terms"
// Example: emit 'in' only as keyword when context says we are in a for-header
export const forKeywordTokenizer = new ExternalTokenizer(
(input, stack) => {
const ctx = stack.context as { inForHeader: boolean } | null
if (!ctx?.inForHeader) return
// Match "in" literally
if (input.next === 105 /* 'i' */) {
input.advance()
if (input.next === 110 /* 'n' */) {
input.advance()
// Ensure it's not part of a longer identifier
const next = input.next
if (next < 65 || (next > 90 && next < 97) || next > 122) {
input.acceptToken(kwIn)
}
}
}
},
{ contextual: true }
)
```
--------------------------------
### Define ParserConfig for LRParser.configure
Source: https://context7.com/lezer-parser/lr/llms.txt
Shows how to define a `ParserConfig` object to customize an `LRParser`. Options are optional and composable, with omitted fields inherited from the base parser. This example includes setting `top`, `dialect`, `strict`, `bufferLength`, `tokenizers`, and `wrap` for mixed-language parsing.
```typescript
import { ParserConfig, ExternalTokenizer } from "@lezer/lr"
import { parseMixed } from "@lezer/common"
const myTokenizer = new ExternalTokenizer((input, stack) => {
// custom tokenizer logic (see ExternalTokenizer section)
})
const config: ParserConfig = {
top: "Module",
dialect: "jsx",
strict: false,
bufferLength: 512,
tokenizers: [{ from: existingTokenizer, to: myTokenizer }],
// Wrap with mixed-language parser (e.g. JS inside HTML)
wrap: parseMixed((node) => {
if (node.type.name === "TemplateString") return { parser: cssParser }
return null
}),
}
const tuned = baseParser.configure(config)
```
--------------------------------
### External Tokenizer with `Stack.canShift`
Source: https://context7.com/lezer-parser/lr/llms.txt
Use `Stack.canShift` to conditionally emit tokens based on parser state. This example emits `templateContent` only when inside a template literal.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { templateContent, noTemplateContent } from "./js.terms"
// Only emit templateContent when the parser is inside a template literal
export const templateTokenizer = new ExternalTokenizer(
(input, stack) => {
if (!stack.canShift(templateContent)) {
input.acceptToken(noTemplateContent)
return
}
let content = ""
while (input.next >= 0 && input.next !== 96 /* ` */ && input.next !== 36 /* $ */) {
input.advance()
}
input.acceptToken(templateContent)
},
{ contextual: true }
)
```
--------------------------------
### External Tokenizer with `Stack.dialectEnabled`
Source: https://context7.com/lezer-parser/lr/llms.txt
Check if a grammar dialect is active using `Stack.dialectEnabled`. This tokenizer only lexes '<' as a JSX open-tag start when the 'jsx' dialect is enabled.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { Dialect_jsx, jsxOpenTag } from "./javascript.terms"
import { lessThan } from "./javascript.terms"
// Only lex '<' as JSX open-tag start when jsx dialect is enabled
export const jsxTokenizer = new ExternalTokenizer(
(input, stack) => {
if (input.next !== 60 /* '<' */) return
if (!stack.dialectEnabled(Dialect_jsx)) {
// Fall through to normal '<' tokenizer
return
}
input.advance()
// Further JSX tag scanning…
input.acceptToken(jsxOpenTag)
},
{ fallback: true }
)
```
--------------------------------
### Configure LRParser with Custom Settings
Source: https://context7.com/lezer-parser/lr/llms.txt
Demonstrates creating a reconfigured `LRParser` instance with modified settings like `top` rule, `dialect`, `props`, `strict` mode, `tokenizers`, and `bufferLength`. The original parser remains unmodified.
```typescript
import { parser } from "./generated-parser"
import { NodeProp } from "@lezer/common"
// Add a custom node prop to all nodes
const indentProp = new NodeProp({ deserialize: n => Number(n) })
const configuredParser = parser.configure({
// Parse from a specific @top rule (if grammar defines multiple)
top: "Expression",
// Enable a grammar dialect (e.g. TypeScript-specific syntax)
dialect: "ts",
// Add node props (for e.g. indentation, highlighting)
props: [indentProp.add({ FunctionBody: 2, Block: 2 })],
// Strict mode: throw instead of error-recover on invalid input
strict: false,
// Replace an external tokenizer at runtime
tokenizers: [{ from: oldTokenizer, to: newTokenizer }],
// Increase tree buffer size (default: 1024)
bufferLength: 2048,
})
const tree = configuredParser.parse("x + y")
console.log(configuredParser.topNode.name) // → "Expression"
```
--------------------------------
### Incremental Parse with LRParser
Source: https://context7.com/lezer-parser/lr/llms.txt
Shows how to perform an incremental parse using `startParse` and `advance` for editor integration. The `advance` method returns a `Tree` when parsing is complete, or `null` otherwise.
```typescript
// --- Incremental / partial parse (for editor integration) ---
const partialParse = parser.startParse(input)
let result = null
while (!result) {
result = partialParse.advance() // returns Tree when done, null otherwise
}
console.log(result.type.name) // → "Script"
```
--------------------------------
### LRParser.configure
Source: https://context7.com/lezer-parser/lr/llms.txt
Creates a reconfigured copy of an LRParser instance with specified settings changed, such as the top rule, grammar dialects, external tokenizers, node props, strict mode, and parse wrappers.
```APIDOC
## `LRParser.configure` — Create a reconfigured parser copy
Returns a new `LRParser` instance with the specified settings changed, leaving the original parser unmodified. Supports changing the top rule, enabling grammar dialects, replacing external tokenizers or specializers, adding node props, toggling strict mode, and attaching parse wrappers for mixed-language parsing.
```typescript
import { parser } from "./generated-parser"
import { NodeProp } from "@lezer/common"
// Add a custom node prop to all nodes
const indentProp = new NodeProp({ deserialize: n => Number(n) })
const configuredParser = parser.configure({
// Parse from a specific @top rule (if grammar defines multiple)
top: "Expression",
// Enable a grammar dialect (e.g. TypeScript-specific syntax)
dialect: "ts",
// Add node props (for e.g. indentation, highlighting)
props: [indentProp.add({ FunctionBody: 2, Block: 2 })],
// Strict mode: throw instead of error-recover on invalid input
strict: false,
// Replace an external tokenizer at runtime
tokenizers: [{ from: oldTokenizer, to: newTokenizer }],
// Increase tree buffer size (default: 1024)
bufferLength: 2048,
})
const tree = configuredParser.parse("x + y")
console.log(configuredParser.topNode.name) // → "Expression"
```
```
--------------------------------
### Full Synchronous Parse with LRParser
Source: https://context7.com/lezer-parser/lr/llms.txt
Demonstrates a complete synchronous parse of a string input using the LRParser. Ensure the parser is imported from a generated JavaScript file.
```typescript
import { parser } from "./generated-javascript-parser" // produced by @lezer/generator
import { StringInput } from "@lezer/common"
// --- Full synchronous parse ---
const input = "let x = 1 + 2;"
const tree = parser.parse(input)
console.log(tree.toString())
// → "Script(VariableDeclaration(let,VariableDeclarator(x,BinaryExpression(1,+,2))))"
```
--------------------------------
### Incremental Parsing with TreeFragment
Source: https://context7.com/lezer-parser/lr/llms.txt
Demonstrates how to use `TreeFragment` for incremental parsing, allowing reuse of previous parse trees when the document changes. `TreeFragment.applyChanges` computes valid fragments from a previous `Tree` given document changes.
```APIDOC
## Incremental Parsing with `TreeFragment` — Reuse previous parse trees
Lezer's key editor feature is incremental parsing: when the document changes, only the affected region is re-parsed, and subtrees from the previous parse are reused where safe. `TreeFragment.applyChanges` computes the still-valid fragments from a previous `Tree` given a list of document changes, which are then passed to `startParse`.
```typescript
import { parser } from "./generated-parser"
import { TreeFragment } from "@lezer/common"
let source = "function foo() { return 1; }"
let tree = parser.parse(source)
let fragments = TreeFragment.addTree(tree)
// Simulate a document edit: replace "1" with "42"
const changes = [{ fromA: 24, toA: 25, fromB: 24, toB: 26 }]
source = "function foo() { return 42; }"
// Apply changes to existing fragments
fragments = TreeFragment.applyChanges(fragments, changes)
// Re-parse with fragments; subtrees outside the edit region are reused
const updatedTree = parser.parse(source, fragments)
console.log(updatedTree.toString())
// → "Script(FunctionDeclaration(foo,ParamList,Block(ReturnStatement(42))))"
```
```
--------------------------------
### LRParser - Main parser class
Source: https://context7.com/lezer-parser/lr/llms.txt
The LRParser class holds parse tables and is the main entry point for parsing. It extends the abstract Parser class and is created using LRParser.deserialize. The parse and startParse methods drive the parsing process.
```APIDOC
## LRParser — Main parser class
`LRParser` holds the parse tables for a grammar and is the primary entry point for parsing. It extends the abstract `Parser` class from `@lezer/common`. Instances are created by calling `LRParser.deserialize` with the data object emitted by `@lezer/generator`; they are immutable and reusable across parses. The `parse` and `startParse` methods (inherited from `@lezer/common`) drive actual parsing.
```typescript
import { parser } from "./generated-javascript-parser" // produced by @lezer/generator
import { StringInput } from "@lezer/common"
// --- Full synchronous parse ---
const input = "let x = 1 + 2;"
const tree = parser.parse(input)
console.log(tree.toString())
// → "Script(VariableDeclaration(let,VariableDeclarator(x,BinaryExpression(1,+,2))))"
// --- Incremental / partial parse (for editor integration) ---
const partialParse = parser.startParse(input)
let result = null
while (!result) {
result = partialParse.advance() // returns Tree when done, null otherwise
}
console.log(result.type.name) // → "Script"
// --- Parse with position ranges (e.g. embedded language regions) ---
const tree2 = parser.parse(input, [], [
{ from: 0, to: 8 },
{ from: 12, to: input.length }
])
```
```
--------------------------------
### Tokenize Rust-style Raw Strings with ExternalTokenizer
Source: https://context7.com/lezer-parser/lr/llms.txt
Create a tokenizer for Rust-style raw string literals (r"...") using ExternalTokenizer. This tokenizer handles varying numbers of '#' characters between 'r' and the opening quote, and ensures the closing quote is matched by the same number of hashes. It requires a token ID for raw strings.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { rawString } from "./my-grammar.terms"
// Tokenize a raw string literal: r"..."# (Rust-style)
export const rawStringTokenizer = new ExternalTokenizer((input) => {
if (input.next !== 114 /* 'r' */) return // must start with 'r'
input.advance()
let hashCount = 0
while (input.next === 35 /* '#' */) { hashCount++; input.advance() }
if (input.next !== 34 /* '"' */) return // must have opening quote
input.advance()
// Scan until we find the matching closing quote + hashes
outer: for (;;) {
if (input.next < 0) return // unexpected EOF
if (input.next === 34 /* '"' */) {
input.advance()
let closeHashes = 0
while (input.next === 35 && closeHashes < hashCount) {
closeHashes++
input.advance()
}
if (closeHashes === hashCount) break outer
} else {
input.advance()
}
}
input.acceptToken(rawString) // emit token ending at current pos
})
```
--------------------------------
### Manage Indentation Context with ContextTracker
Source: https://context7.com/lezer-parser/lr/llms.txt
Implement indentation-sensitive parsing using ContextTracker for languages like Python. This tracker maintains the current indentation depth and a stack of previous depths, updating them on indent and dedent tokens. It requires token IDs for indent and dedent, and a helper function to count spaces.
```typescript
import { ContextTracker } from "@lezer/lr"
import { indent, dedent } from "./python-grammar.terms"
interface IndentContext {
readonly depth: number
readonly stack: readonly number[]
}
export const indentTracker = new ContextTracker({
start: { depth: 0, stack: [] },
// Called when the parser shifts a token
shift(context, term, _stack, input) {
if (term === indent) {
// Push new indentation level on shift of INDENT token
const col = countSpaces(input.read(input.pos, input.pos + 40))
return { depth: col, stack: [...context.stack, context.depth] }
}
if (term === dedent) {
// Pop indentation level on DEDENT
const stack = context.stack.slice()
return { depth: stack.pop() ?? 0, stack }
}
return context
},
// Cheap numeric hash for efficient incremental-reuse comparison
hash(context) {
return context.depth
},
strict: true, // only reuse nodes parsed in the same context
})
function countSpaces(str: string) {
let n = 0
for (const ch of str) { if (ch === " ") n++; else break }
return n
}
```
--------------------------------
### InputStream
Source: https://context7.com/lezer-parser/lr/llms.txt
InputStream provides a navigable stream of Unicode code units for tokenizers. It allows inspection and consumption of characters, handling non-contiguous ranges transparently. Key members include next, pos, peek, advance, acceptToken, and acceptTokenTo.
```APIDOC
## `InputStream` — Character stream interface for tokenizers
`InputStream` presents the document being parsed as a navigable stream of Unicode code units. Tokenizer functions use it to inspect and consume characters. It transparently handles documents parsed in non-contiguous ranges (e.g. embedded language regions). Key members: `next` (current char code or -1), `pos` (current position), `peek(offset)`, `advance(n?)`, `acceptToken(type, endOffset?)`, `acceptTokenTo(type, endPos)`.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { rawString } from "./my-grammar.terms"
// Tokenize a raw string literal: r#"..."# (Rust-style)
export const rawStringTokenizer = new ExternalTokenizer((input) => {
if (input.next !== 114 /* 'r' */) return // must start with 'r'
input.advance()
let hashCount = 0
while (input.next === 35 /* '#' */) { hashCount++; input.advance() }
if (input.next !== 34 /* '"' */) return // must have opening quote
input.advance()
// Scan until we find the matching closing quote + hashes
outer: for (;;) {
if (input.next < 0) return // unexpected EOF
if (input.next === 34 /* '"' */) {
input.advance()
let closeHashes = 0
while (input.next === 35 && closeHashes < hashCount) {
closeHashes++
input.advance()
}
if (closeHashes === hashCount) break outer
} else {
input.advance()
}
}
input.acceptToken(rawString) // emit token ending at current pos
})
```
```
--------------------------------
### ContextTracker
Source: https://context7.com/lezer-parser/lr/llms.txt
ContextTracker maintains a stateful value that evolves with the parser, accessible via stack.context. It's declared using @context and used for indentation-sensitive languages or tracking parent elements. Context values must be treated as immutable.
```APIDOC
## `ContextTracker` — Stateful parse context for tokenizers
`ContextTracker` maintains a stateful value that evolves as the parser shifts and reduces, accessible to `ExternalTokenizer`s via `stack.context`. It is declared in a Lezer grammar as `@context exportName from "module"`. Context values must be treated as immutable; callbacks return new values rather than mutating. Used for indentation-sensitive languages (Python), parent-element tracking (XML/HTML), etc.
```typescript
import { ContextTracker } from "@lezer/lr"
import { indent, dedent } from "./python-grammar.terms"
interface IndentContext {
readonly depth: number
readonly stack: readonly number[]
}
export const indentTracker = new ContextTracker({
start: { depth: 0, stack: [] },
// Called when the parser shifts a token
shift(context, term, _stack, input) {
if (term === indent) {
// Push new indentation level on shift of INDENT token
const col = countSpaces(input.read(input.pos, input.pos + 40))
return { depth: col, stack: [...context.stack, context.depth] }
}
if (term === dedent) {
// Pop indentation level on DEDENT
const stack = context.stack.slice()
return { depth: stack.pop() ?? 0, stack }
}
return context
},
// Cheap numeric hash for efficient incremental-reuse comparison
hash(context) {
return context.depth
},
strict: true, // only reuse nodes parsed in the same context
})
function countSpaces(str: string) {
let n = 0
for (const ch of str) { if (ch === " ") n++; else break }
return n
}
```
```
--------------------------------
### Incremental Parsing with `TreeFragment`
Source: https://context7.com/lezer-parser/lr/llms.txt
Reuse previous parse trees for efficient incremental parsing. `TreeFragment.applyChanges` computes valid fragments after document edits, which are then used by `parser.parse`.
```typescript
import { parser } from "./generated-parser"
import { TreeFragment } from "@lezer/common"
let source = "function foo() { return 1; }"
let tree = parser.parse(source)
let fragments = TreeFragment.addTree(tree)
// Simulate a document edit: replace "1" with "42"
const changes = [{ fromA: 24, toA: 25, fromB: 24, toB: 26 }]
source = "function foo() { return 42; }"
// Apply changes to existing fragments
fragments = TreeFragment.applyChanges(fragments, changes)
// Re-parse with fragments; subtrees outside the edit region are reused
const updatedTree = parser.parse(source, fragments)
console.log(updatedTree.toString())
// → "Script(FunctionDeclaration(foo,ParamList,Block(ReturnStatement(42))))"
```
--------------------------------
### Parse with Position Ranges using LRParser
Source: https://context7.com/lezer-parser/lr/llms.txt
Illustrates parsing a string while specifying position ranges, useful for handling embedded language regions. The `parse` method accepts an array of `from` and `to` objects.
```typescript
// --- Parse with position ranges (e.g. embedded language regions) ---
const tree2 = parser.parse(input, [], [
{ from: 0, to: 8 },
{ from: 12, to: input.length }
])
```
--------------------------------
### ParserConfig Interface
Source: https://context7.com/lezer-parser/lr/llms.txt
The ParserConfig interface defines the options accepted by LRParser.configure, allowing customization of parser behavior like top rule, dialect, strict mode, tokenizers, and parse wrappers.
```APIDOC
## `ParserConfig` — Configuration interface for `LRParser.configure`
`ParserConfig` is the TypeScript interface describing all options accepted by `LRParser.configure`. Options are individually optional and composable; omitted fields are inherited from the base parser.
```typescript
import { ParserConfig, ExternalTokenizer } from "@lezer/lr"
import { parseMixed } from "@lezer/common"
const myTokenizer = new ExternalTokenizer((input, stack) => {
// custom tokenizer logic (see ExternalTokenizer section)
})
const config: ParserConfig = {
top: "Module",
dialect: "jsx",
strict: false,
bufferLength: 512,
tokenizers: [{ from: existingTokenizer, to: myTokenizer }],
// Wrap with mixed-language parser (e.g. JS inside HTML)
wrap: parseMixed((node) => {
if (node.type.name === "TemplateString") return { parser: cssParser }
return null
}),
}
const tuned = baseParser.configure(config)
```
```
--------------------------------
### Stack.canShift
Source: https://context7.com/lezer-parser/lr/llms.txt
Checks if shifting a given terminal is a valid action from the current parse state, considering pending reductions. This is useful for external tokenizers to make context-sensitive decisions.
```APIDOC
## `Stack.canShift` — Check whether a token can be accepted
`Stack.canShift(term)` returns `true` if shifting the given terminal (by numeric term ID) is a valid action from the current parse state, accounting for any pending reductions. This is the primary way external tokenizers make context-sensitive decisions about which tokens to emit.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { templateContent, noTemplateContent } from "./js.terms"
// Only emit templateContent when the parser is inside a template literal
export const templateTokenizer = new ExternalTokenizer(
(input, stack) => {
if (!stack.canShift(templateContent)) {
input.acceptToken(noTemplateContent)
return
}
let content = ""
while (input.next >= 0 && input.next !== 96 /* ` */ && input.next !== 36 /* $ */) {
input.advance()
}
input.acceptToken(templateContent)
},
{ contextual: true }
)
```
```
--------------------------------
### Stack.context
Source: https://context7.com/lezer-parser/lr/llms.txt
Accesses the current value maintained by the grammar's ContextTracker. Returns `null` if no context tracker is configured. Useful for external tokenizers to make decisions based on accumulated parse state.
```APIDOC
## `Stack.context` — Access the current context tracker value
`Stack.context` returns the current value maintained by the grammar's `ContextTracker`, or `null` if no context tracker is configured. The type matches the generic parameter `T` of the `ContextTracker` used by the grammar. Useful in external tokenizers to make decisions based on accumulated parse state.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { identifier, kwIn } from "./my-grammar.terms"
// Example: emit 'in' only as keyword when context says we are in a for-header
export const forKeywordTokenizer = new ExternalTokenizer(
(input, stack) => {
const ctx = stack.context as { inForHeader: boolean } | null
if (!ctx?.inForHeader) return
// Match "in" literally
if (input.next === 105 /* 'i' */) {
input.advance()
if (input.next === 110 /* 'n' */) {
input.advance()
// Ensure it's not part of a longer identifier
const next = input.next
if (next < 65 || (next > 90 && next < 97) || next > 122) {
input.acceptToken(kwIn)
}
}
}
},
{ contextual: true }
)
```
```
--------------------------------
### ExternalTokenizer
Source: https://context7.com/lezer-parser/lr/llms.txt
ExternalTokenizer wraps a tokenizer function for @external tokens declarations. It allows custom logic to read from an InputStream and emit tokens using acceptToken. Options control caching, priority, and parallel execution.
```APIDOC
## `ExternalTokenizer` — Custom tokenizer for `@external tokens`
`ExternalTokenizer` wraps a tokenizer function referenced by an `@external tokens` declaration in a Lezer grammar. The function receives an `InputStream` and a `Stack`, reads characters from the stream, and calls `input.acceptToken(tokenType)` to emit a token. Options control caching behavior (`contextual`), priority (`fallback`), and parallel running (`extend`).
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { InputStream } from "@lezer/lr"
// Token IDs come from the generated terms file
import { insertSemicolon, noSemicolon } from "./generated-parser.terms"
// Automatic semicolon insertion tokenizer (JavaScript-style)
export const semicolonTokenizer = new ExternalTokenizer(
(input: InputStream, stack) => {
const prev = input.peek(-1) // look behind 1 char
// If the previous character was a newline and the stack allows a semicolon
if (
(prev === 10 /* \n */ || prev === 13 /* \r */ || prev === -1 /* EOF */) &&
stack.canShift(insertSemicolon)
) {
input.acceptToken(insertSemicolon)
} else {
input.acceptToken(noSemicolon)
}
},
{
contextual: true, // don't cache; result depends on parse stack state
fallback: false, // run with normal priority
extend: false, // stop other tokenizers after this one matches
}
)
```
```
--------------------------------
### Implement Automatic Semicolon Insertion with ExternalTokenizer
Source: https://context7.com/lezer-parser/lr/llms.txt
Use ExternalTokenizer to implement JavaScript-style automatic semicolon insertion. This tokenizer checks the previous character and the parser stack to decide whether to insert a semicolon token. It requires token IDs from a generated terms file.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { InputStream } from "@lezer/lr"
// Token IDs come from the generated terms file
import { insertSemicolon, noSemicolon } from "./generated-parser.terms"
// Automatic semicolon insertion tokenizer (JavaScript-style)
export const semicolonTokenizer = new ExternalTokenizer(
(input: InputStream, stack) => {
const prev = input.peek(-1) // look behind 1 char
// If the previous character was a newline and the stack allows a semicolon
if (
(prev === 10 /* \n */ || prev === 13 /* \r */ || prev === -1 /* EOF */) &&
stack.canShift(insertSemicolon)
) {
input.acceptToken(insertSemicolon)
} else {
input.acceptToken(noSemicolon)
}
},
{
contextual: true, // don't cache; result depends on parse stack state
fallback: false, // run with normal priority
extend: false, // stop other tokenizers after this one matches
}
)
```
--------------------------------
### Stack.dialectEnabled
Source: https://context7.com/lezer-parser/lr/llms.txt
Tests if a grammar dialect is active. Returns `true` if the specified dialect ID is currently enabled on the parser. Used to conditionally emit dialect-specific tokens.
```APIDOC
## `Stack.dialectEnabled` — Test if a grammar dialect is active
`Stack.dialectEnabled(dialectID)` returns `true` when the given dialect (identified by its numeric ID as exported from the grammar's terms file) is currently enabled on the parser. Used inside tokenizers or specializers to conditionally emit dialect-specific tokens.
```typescript
import { ExternalTokenizer } from "@lezer/lr"
import { Dialect_jsx, jsxOpenTag } from "./javascript.terms"
import { lessThan } from "./javascript.terms"
// Only lex '<' as JSX open-tag start when jsx dialect is enabled
export const jsxTokenizer = new ExternalTokenizer(
(input, stack) => {
if (input.next !== 60 /* '<' */) return
if (!stack.dialectEnabled(Dialect_jsx)) {
// Fall through to normal '<' tokenizer
return
}
input.advance()
// Further JSX tag scanning…
input.acceptToken(jsxOpenTag)
},
{ fallback: true }
)
// Enabling the dialect when building the parser:
import { parser } from "./javascript-parser"
const jsxParser = parser.configure({ dialect: "jsx" })
const tree = jsxParser.parse("hello
")
```
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.