Error Handling
Handling parse errors and debugging grammars
Error Handling
This page covers error handling, debugging, and troubleshooting in Galore.
ParseError
When parsing fails, Galore throws a ParseError:
import { newParser, ParseError } from "galore";
const [parser] = newParser(grammar);
try {
const result = parser.parse("invalid input");
} catch (err) {
if (err instanceof ParseError) {
console.log(err.message); // Error description
console.log(err.type); // Error type (e.g., "UnexpectedToken")
console.log(err.value); // Additional context
}
}
Error Types
| Type | Description |
|---|---|
UnexpectedToken |
Parser encountered a token it didn't expect |
TokenizerError |
Lexer couldn't match input (from TLEX) |
Error Value
The value property contains context about the error:
catch (err) {
if (err instanceof ParseError && err.type === "UnexpectedToken") {
const { state, token } = err.value;
console.log(`State: ${state}`);
console.log(`Token: ${token.tag} = "${token.value}"`);
console.log(`Position: ${token.start}-${token.end}`);
}
}
Error Callbacks
onTokenError
Handle lexer errors (invalid characters) without throwing:
const result = parser.parse(input, {
ruleHandlers: {},
onTokenError: (err, tape) => {
console.warn(`Skipping invalid character at position ${tape.offset}`);
// Skip the invalid character and continue
tape.advance();
// Return true to retry tokenization
return true;
}
});
Return true to retry after handling, or false (or throw) to abort.
actionResolver
Handle parse table conflicts at runtime:
const result = parser.parse(input, {
ruleHandlers: {},
actionResolver: (actions, stack, tokenbuffer) => {
// Multiple actions available (conflict)
console.log("Conflict:", actions.map(a => a.toString()));
// Choose based on context
// Prefer shift over reduce (default behavior for many parsers)
const shift = actions.find(a => a.tag === LRActionType.SHIFT);
if (shift) return shift;
// Otherwise take first action
return actions[0];
}
});
Debug Output
Enable debug output to see lexer and parser internals:
const [parser] = newParser(grammar, {
type: "lalr",
debug: "all" // "all" | "lexer" | "parser"
});
Debug Options
| Value | Output |
|---|---|
"lexer" |
Tokenizer program and token stream |
"parser" |
Parse table and state transitions |
"all" |
Both lexer and parser output |
Common Errors
Unexpected Token
The parser received a token that doesn't match any expected symbol in the current state.
Causes:
- Input doesn't match the grammar
- Missing token definition
- Incorrect grammar rule
Debugging:
- Check the token that caused the error
- Verify the grammar accepts that token in context
- Use the Playground to test the grammar
Action Handler Not Found
Error: Action handler not found: handlerName
A grammar rule has a { handlerName } action but no matching function in ruleHandlers.
Fix: Provide all required handlers:
parser.parse(input, {
ruleHandlers: {
handlerName: (rule, parent, ...children) => {
// Handle the reduction
}
}
});
Multiple Actions Found
Error: Multiple actions found.
The parse table has a conflict (shift-reduce or reduce-reduce) and no actionResolver was provided.
Fix: Either resolve the grammar conflict or provide an actionResolver:
parser.parse(input, {
ruleHandlers: {},
actionResolver: (actions) => actions[0] // Take first action
});
See Parse Tables for conflict resolution strategies.
Invalid Token Tag
Error: Invalid token tag: UNKNOWN
The lexer produced a token with a tag that doesn't match any terminal in the grammar.
Fix: Ensure token names match between lexer and grammar.
Using the Playground
The Interactive Playground is the best tool for debugging grammars:
- Parse table visualization - See all states and actions
- Conflict highlighting - Cells with conflicts are highlighted in amber
- LR item hints - Hover over states to see item sets
- Live parsing - Test inputs and see parse trees immediately
Checking for Conflicts
Programmatically check if a grammar has conflicts:
import { newParser } from "galore";
const [parser, tokenFunc, itemGraph] = newParser(grammar, { type: "lalr" });
if (parser.parseTable.hasConflicts) {
console.log("Grammar has conflicts!");
console.log(parser.parseTable.conflictActions);
}