Parser generator for JavaScript that produces fast parsers with excellent error reporting capabilities
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Low-level grammar parsing functionality for converting PEG grammar strings into Abstract Syntax Trees. The parser namespace provides direct access to Peggy's grammar parser and syntax error handling.
Parses PEG grammar definitions into AST representations for further processing by the compiler.
namespace parser {
/**
* Parses grammar and returns the grammar AST
* @param grammar - Source text of the PEG grammar
* @param options - Parser options for grammar parsing
* @returns Grammar AST ready for compilation
* @throws {SyntaxError} If grammar has incorrect syntax
*/
function parse(grammar: string, options?: Options): ast.Grammar;
/**
* Parser options for grammar parsing
*/
interface Options {
/** Source identifier attached to LocationRange objects */
grammarSource?: any;
/** Words not allowed as label names */
reservedWords: string[];
/** Start rule - must be "Grammar" */
startRule?: "Grammar";
}
}Usage Examples:
import { parser } from "peggy";
// Basic grammar parsing
const grammar = `
start = "hello" " " name:[a-z]+ { return "Hello, " + name.join(""); }
`;
try {
const ast = parser.parse(grammar, {
reservedWords: ["function", "class", "var"],
grammarSource: "my-grammar.peggy"
});
console.log(ast.rules.length); // Number of rules
console.log(ast.rules[0].name); // "start"
} catch (error) {
console.error("Parse error:", error.message);
}Detailed syntax error reporting with location information and expectation details.
namespace parser {
/**
* Grammar syntax error with detailed location and expectation info
*/
class SyntaxError extends globalThis.SyntaxError {
/** Location where error occurred */
location: LocationRange;
/** Possible tokens expected at error location */
expected: Expectation[] | null;
/** Character found at error location */
found: string | null;
constructor(
message: string,
expected: Expectation[] | null,
found: string | null,
location: LocationRange
);
/**
* Format error with source context
* @param sources - Source text mapping for context
* @returns Formatted error with source lines
*/
format(sources: SourceText[]): string;
/**
* Build human-readable message from expectations
* @param expected - Array of expected items
* @param found - Text found instead of expected
* @returns Human-readable error message
*/
static buildMessage(expected: Expectation[], found: string): string;
}
}Error Handling Example:
import { parser } from "peggy";
try {
const ast = parser.parse("start = @invalid", {
reservedWords: [],
grammarSource: "test.peggy"
});
} catch (error) {
if (error instanceof parser.SyntaxError) {
console.log("Syntax error at line", error.location.start.line);
console.log("Expected:", error.expected);
console.log("Found:", error.found);
// Format with source context
const formatted = error.format([{
source: "test.peggy",
text: "start = @invalid"
}]);
console.log(formatted);
}
}Different types of expectations that can appear in syntax errors, describing what the parser was looking for.
namespace parser {
/**
* Union of all expectation types
*/
type Expectation =
| LiteralExpectation
| ClassExpectation
| AnyExpectation
| EndExpectation
| OtherExpectation;
/**
* Expected literal string
*/
interface LiteralExpectation {
type: "literal";
/** Expected sequence of characters */
text: string;
/** If true, case-insensitive matching */
ignoreCase: boolean;
}
/**
* Expected character class
*/
interface ClassExpectation {
type: "class";
/** Character ranges and individual characters */
parts: (string[] | string)[];
/** If true, negated character class */
inverted: boolean;
/** If true, case-insensitive matching */
ignoreCase: boolean;
}
/**
* Expected any character
*/
interface AnyExpectation {
type: "any";
}
/**
* Expected end of input
*/
interface EndExpectation {
type: "end";
}
/**
* Expected other item (from expected() or rule names)
*/
interface OtherExpectation {
type: "other";
/** Human-readable description */
description: string;
}
}The Abstract Syntax Tree structure returned by the parser, representing the complete grammar definition.
The root node representing the entire grammar with all its components.
namespace ast {
/**
* Root grammar AST node
*/
interface Grammar extends Node<"grammar"> {
/** Imported external grammars */
imports: GrammarImport[];
/** Code executed once when importing parser module */
topLevelInitializer?: TopLevelInitializer | TopLevelInitializer[];
/** Code executed each time parse() is called */
initializer?: Initializer | Initializer[];
/** All rules in the grammar */
rules: Rule[];
// Added by compiler passes:
/** Generated JavaScript code and source map */
code?: SourceNode;
/** String literals used in bytecode */
literals?: string[];
/** Character classes used in bytecode */
classes?: GrammarCharacterClass[];
/** Error expectations used in bytecode */
expectations?: GrammarExpectation[];
/** Imported names for library references */
importedNames?: string[];
/** User-defined functions (actions, predicates) */
functions?: FunctionConst[];
/** Location ranges used in bytecode */
locations?: LocationRange[];
}
/**
* Base AST node interface
*/
interface Node<T> {
/** Node type identifier */
type: T;
/** Source location of this node */
location: LocationRange;
}
}Grammar rules and the various expression types that can appear in rule definitions.
namespace ast {
/**
* Grammar rule definition
*/
interface Rule extends Expr<"rule"> {
/** Rule identifier */
name: string;
/** Location of rule name for error reporting */
nameLocation: LocationRange;
/** Rule's parsing expression */
expression: Expression | Named;
/** Generated bytecode (added by compiler) */
bytecode?: number[];
}
/**
* Named rule expression
*/
interface Named extends Expr<"named"> {
/** Human-readable rule name for errors */
name: string;
/** Underlying expression */
expression: Expression;
}
/**
* Union of all expression types
*/
type Expression =
| Action
| Choice
| Labeled
| Prefixed
| Primary
| Repeated
| Sequence
| Suffixed;
/**
* Base expression interface
*/
interface Expr<T> extends Node<T> {
/** Match result estimation (added by compiler) */
match?: MatchResult;
}
/**
* Match result enumeration
*/
enum MatchResult {
ALWAYS = 1, // Always matches
SOMETIMES = 0, // May or may not match
NEVER = -1 // Never matches
}
}The fundamental expression types that form the building blocks of PEG grammars.
namespace ast {
/**
* Union of primary expression types
*/
type Primary =
| Any
| CharacterClass
| Group
| LibraryReference
| Literal
| RuleReference
| SemanticPredicate;
/**
* Reference to another rule
*/
interface RuleReference extends Expr<"rule_ref"> {
/** Name of referenced rule */
name: string;
}
/**
* Reference to rule in imported library
*/
interface LibraryReference extends Expr<"library_ref"> {
/** Rule name (undefined for default rule) */
name: string | undefined;
/** Library namespace name */
library: string;
/** Import statement index */
libraryNumber: number;
}
/**
* Literal string match
*/
interface Literal extends Expr<"literal"> {
/** String to match */
value: string;
/** Case-insensitive matching */
ignoreCase: boolean;
}
/**
* Character class match
*/
interface CharacterClass extends Expr<"class"> {
/** Character ranges and individual characters */
parts: (string[] | string | ClassEscape)[];
/** Negated character class */
inverted: boolean;
/** Case-insensitive matching */
ignoreCase: boolean;
/** Unicode mode */
unicode: boolean;
}
/**
* Match any character
*/
interface Any extends Expr<"any"> {}
/**
* Semantic predicate (code that returns boolean)
*/
interface SemanticPredicate extends CodeBlockExpr<"semantic_and" | "semantic_not"> {}
/**
* Grouping expression for label scoping
*/
interface Group extends Expr<"group"> {
expression: Labeled | Sequence;
}
}AST Usage Example:
import { parser } from "peggy";
const grammar = `
start = "hello" name:word { return "Hello, " + name; }
word = [a-z]+
`;
const ast = parser.parse(grammar, { reservedWords: [] });
// Examine the AST structure
console.log("Number of rules:", ast.rules.length);
console.log("First rule name:", ast.rules[0].name);
console.log("First rule type:", ast.rules[0].expression.type);
// Walk through rules
ast.rules.forEach(rule => {
console.log(`Rule ${rule.name} at line ${rule.location.start.line}`);
});The ast namespace provides comprehensive type definitions for all AST node types in Peggy grammars.
Base interfaces used throughout the AST type system.
namespace ast {
/**
* Base AST node interface
* @template T - Node type identifier
*/
interface Node<T> {
/** Node type identifier */
type: T;
/** Source location of this node */
location: LocationRange;
}
/**
* Base expression node interface
* @template T - Expression type identifier
*/
interface Expr<T> extends Node<T> {
/** Match result estimation (added by compiler passes) */
match?: MatchResult;
}
/**
* Match result enumeration for expressions
*/
enum MatchResult {
ALWAYS = 1, // Expression always matches
SOMETIMES = 0, // Expression may match
NEVER = -1 // Expression never matches
}
}Install with Tessl CLI
npx tessl i tessl/npm-peggy