or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-compilation.mdcli.mdgenerated-parsers.mdgrammar-parsing.mdindex.mdparser-generation.md

ast-compilation.mddocs/

0

# AST Compilation

1

2

Advanced compilation system with multiple passes for transforming, validating, and optimizing grammar ASTs. The `compiler` namespace provides low-level access to Peggy's compilation pipeline and pass system.

3

4

## Capabilities

5

6

### Compile Function

7

8

Compiles grammar ASTs into parser objects or source code through a multi-stage pass system.

9

10

```typescript { .api }

11

namespace compiler {

12

/**

13

* Compiles AST to parser object (default)

14

* @param ast - Grammar AST from parser

15

* @param stages - Compilation stages with passes

16

* @param options - Build options

17

* @returns Generated parser object

18

* @throws {GrammarError} If AST contains semantic errors

19

*/

20

function compile(

21

ast: ast.Grammar,

22

stages: Stages,

23

options?: ParserBuildOptions

24

): Parser;

25

26

/**

27

* Compiles AST to source code string

28

* @param ast - Grammar AST from parser

29

* @param stages - Compilation stages with passes

30

* @param options - Source build options

31

* @returns Generated parser source code

32

*/

33

function compile(

34

ast: ast.Grammar,

35

stages: Stages,

36

options: SourceBuildOptions<"source">

37

): string;

38

39

/**

40

* Compiles AST to SourceNode with source map

41

* @param ast - Grammar AST from parser

42

* @param stages - Compilation stages with passes

43

* @param options - Source build options

44

* @returns SourceNode for code and source map generation

45

*/

46

function compile(

47

ast: ast.Grammar,

48

stages: Stages,

49

options: SourceBuildOptions<"source-and-map">

50

): SourceNode;

51

}

52

```

53

54

**Usage Examples:**

55

56

```typescript

57

import { parser, compiler } from "peggy";

58

59

// Parse grammar to AST

60

const grammar = `start = "hello" " " name:[a-z]+ { return "Hello, " + name.join(""); }`;

61

const ast = parser.parse(grammar, { reservedWords: [] });

62

63

// Compile AST to parser using default passes

64

const parser1 = compiler.compile(ast, compiler.passes);

65

66

// Compile to source code

67

const sourceCode = compiler.compile(ast, compiler.passes, {

68

output: "source",

69

format: "commonjs"

70

});

71

72

// Compile with custom options

73

const cachedParser = compiler.compile(ast, compiler.passes, {

74

cache: true,

75

allowedStartRules: ["start"],

76

trace: true

77

});

78

```

79

80

### Compilation Stages

81

82

Multi-stage compilation pipeline with different types of passes for grammar processing.

83

84

```typescript { .api }

85

namespace compiler {

86

/**

87

* Compilation stages with their passes

88

*/

89

interface Stages {

90

/** Preparation passes for linking and setup */

91

prepare: Pass[];

92

/** Validation passes for error checking */

93

check: Pass[];

94

/** AST transformation passes */

95

transform: Pass[];

96

/** Code generation passes */

97

generate: Pass[];

98

}

99

100

/**

101

* Default compilation stages

102

*/

103

let passes: Stages;

104

105

/**

106

* Compilation pass function

107

* @param ast - Grammar AST to process (may be modified)

108

* @param options - Build options from generate() call

109

* @param session - Session for error/warning reporting

110

*/

111

type Pass = (

112

ast: ast.Grammar,

113

options: ParserBuildOptions,

114

session: Session

115

) => void;

116

}

117

```

118

119

**Default Passes:**

120

121

The default `compiler.passes` object includes these built-in passes:

122

123

```typescript

124

// Prepare stage

125

const prepare = [

126

"addImportedRules", // Add rules from imported grammars

127

"reportInfiniteRecursion" // Detect infinite recursion

128

];

129

130

// Check stage

131

const check = [

132

"reportUndefinedRules", // Check for undefined rule references

133

"reportDuplicateRules", // Check for duplicate rule definitions

134

"reportDuplicateLabels", // Check for duplicate labels in rules

135

"reportInfiniteRepetition", // Check for infinite repetition

136

"reportIncorrectPlucking", // Check for incorrect @ usage

137

"reportDuplicateImports" // Check for duplicate import statements

138

];

139

140

// Transform stage

141

const transform = [

142

"fixLibraryNumbers", // Fix library reference numbers

143

"removeProxyRules", // Remove unnecessary proxy rules

144

"mergeCharacterClasses", // Optimize character classes

145

"removeUnusedRules", // Remove unreferenced rules

146

"inferenceMatchResult" // Infer match results for expressions

147

];

148

149

// Generate stage

150

const generate = [

151

"generateBytecode", // Generate bytecode for expressions

152

"generateJS" // Generate JavaScript parser code

153

];

154

```

155

156

### Compilation Session

157

158

Session object for pass execution that provides error reporting and diagnostic capabilities.

159

160

```typescript { .api }

161

namespace compiler {

162

/**

163

* Compilation session for pass execution

164

*/

165

interface Session {

166

/** All problems registered during compilation */

167

problems: Problem[];

168

169

/**

170

* Report compilation error

171

* @param message - Error description

172

* @param location - Source location if applicable

173

* @param notes - Additional diagnostic information

174

*/

175

error(

176

message: string,

177

location?: LocationRange,

178

notes?: DiagnosticNote[]

179

): void;

180

181

/**

182

* Report compilation warning

183

* @param message - Warning description

184

* @param location - Source location if applicable

185

* @param notes - Additional diagnostic information

186

*/

187

warning(

188

message: string,

189

location?: LocationRange,

190

notes?: DiagnosticNote[]

191

): void;

192

193

/**

194

* Report informational message

195

* @param message - Information description

196

* @param location - Source location if applicable

197

* @param notes - Additional diagnostic information

198

*/

199

info(

200

message: string,

201

location?: LocationRange,

202

notes?: DiagnosticNote[]

203

): void;

204

}

205

206

/**

207

* Problem reported during compilation

208

*/

209

type Problem = [

210

severity: "error" | "info" | "warning",

211

message: string,

212

location?: LocationRange,

213

diagnostics?: DiagnosticNote[]

214

];

215

216

/**

217

* Additional diagnostic note with location

218

*/

219

interface DiagnosticNote {

220

message: string;

221

location: LocationRange;

222

}

223

}

224

```

225

226

**Custom Pass Example:**

227

228

```typescript

229

import { parser, compiler } from "peggy";

230

231

// Custom pass that logs rule information

232

const logRulesPass = (ast, options, session) => {

233

session.info(`Processing ${ast.rules.length} rules`);

234

235

ast.rules.forEach(rule => {

236

if (rule.name.startsWith("_")) {

237

session.warning(`Private rule detected: ${rule.name}`, rule.nameLocation);

238

}

239

});

240

};

241

242

// Create custom stages with additional pass

243

const customStages = {

244

...compiler.passes,

245

check: [...compiler.passes.check, logRulesPass]

246

};

247

248

// Use custom stages

249

const ast = parser.parse(grammar, { reservedWords: [] });

250

const parser1 = compiler.compile(ast, customStages, {

251

info: (stage, message) => console.log(`[${stage}] ${message}`),

252

warning: (stage, message, location) => console.warn(`Warning: ${message}`)

253

});

254

```

255

256

### AST Visitor System

257

258

Visitor pattern implementation for traversing and manipulating grammar ASTs.

259

260

```typescript { .api }

261

namespace compiler {

262

namespace visitor {

263

/**

264

* Visitor function builder

265

* @param functions - Object with visitor functions for node types

266

* @returns Visitor function for AST traversal

267

*/

268

function build<F extends NodeTypes>(functions: F): Visitor<F>;

269

270

/**

271

* Visitor function for AST nodes

272

*/

273

interface Visitor<F extends NodeTypes> {

274

/**

275

* Visit AST node with type-specific visitor

276

* @param node - AST node to visit

277

* @param args - Additional arguments for visitor

278

* @returns Result from visitor function

279

*/

280

<T extends keyof NodeTypes>(

281

node: ast.Node<T>,

282

...args: any[]

283

): ReturnType<AnyFunction & F[T]>;

284

}

285

286

/**

287

* Visitor functions for different node types

288

*/

289

interface NodeTypes {

290

/** Visit grammar root */

291

grammar?(node: ast.Grammar, ...args: any[]): any;

292

/** Visit import statement */

293

grammar_import?(node: ast.GrammarImport, ...args: any[]): any;

294

/** Visit top-level initializer */

295

top_level_initializer?(node: ast.TopLevelInitializer, ...args: any[]): any;

296

/** Visit per-parse initializer */

297

initializer?(node: ast.Initializer, ...args: any[]): any;

298

/** Visit rule */

299

rule?(node: ast.Rule, ...args: any[]): any;

300

/** Visit named expression */

301

named?(node: ast.Named, ...args: any[]): any;

302

/** Visit choice expression */

303

choice?(node: ast.Choice, ...args: any[]): any;

304

/** Visit action expression */

305

action?(node: ast.Action, ...args: any[]): any;

306

/** Visit sequence expression */

307

sequence?(node: ast.Sequence, ...args: any[]): any;

308

/** Visit labeled expression */

309

labeled?(node: ast.Labeled, ...args: any[]): any;

310

/** Visit text expression */

311

text?(node: ast.Prefixed, ...args: any[]): any;

312

/** Visit positive lookahead */

313

simple_and?(node: ast.Prefixed, ...args: any[]): any;

314

/** Visit negative lookahead */

315

simple_not?(node: ast.Prefixed, ...args: any[]): any;

316

/** Visit optional expression */

317

optional?(node: ast.Suffixed, ...args: any[]): any;

318

/** Visit zero-or-more expression */

319

zero_or_more?(node: ast.Suffixed, ...args: any[]): any;

320

/** Visit one-or-more expression */

321

one_or_more?(node: ast.Suffixed, ...args: any[]): any;

322

/** Visit repeated expression */

323

repeated?(node: ast.Repeated, ...args: any[]): any;

324

/** Visit group expression */

325

group?(node: ast.Group, ...args: any[]): any;

326

/** Visit semantic AND predicate */

327

semantic_and?(node: ast.SemanticPredicate, ...args: any[]): any;

328

/** Visit semantic NOT predicate */

329

semantic_not?(node: ast.SemanticPredicate, ...args: any[]): any;

330

/** Visit rule reference */

331

rule_ref?(node: ast.RuleReference, ...args: any[]): any;

332

/** Visit library reference */

333

library_ref?(node: ast.LibraryReference, ...args: any[]): any;

334

/** Visit literal */

335

literal?(node: ast.Literal, ...args: any[]): any;

336

/** Visit character class */

337

class?(node: ast.CharacterClass, ...args: any[]): any;

338

/** Visit any-character */

339

any?(node: ast.Any, ...args: any[]): any;

340

}

341

}

342

}

343

```

344

345

**Visitor Usage Example:**

346

347

```typescript

348

import { parser, compiler } from "peggy";

349

350

// Create visitor that counts different expression types

351

const expressionCounter = compiler.visitor.build({

352

rule(node, counts) {

353

counts.rules++;

354

return this(node.expression, counts);

355

},

356

357

literal(node, counts) {

358

counts.literals++;

359

},

360

361

class(node, counts) {

362

counts.classes++;

363

},

364

365

rule_ref(node, counts) {

366

counts.references++;

367

},

368

369

choice(node, counts) {

370

counts.choices++;

371

node.alternatives.forEach(alt => this(alt, counts));

372

},

373

374

sequence(node, counts) {

375

counts.sequences++;

376

node.elements.forEach(elem => this(elem, counts));

377

}

378

});

379

380

// Use visitor on parsed grammar

381

const ast = parser.parse(complexGrammar, { reservedWords: [] });

382

const counts = {

383

rules: 0,

384

literals: 0,

385

classes: 0,

386

references: 0,

387

choices: 0,

388

sequences: 0

389

};

390

391

expressionCounter(ast, counts);

392

console.log("Expression counts:", counts);

393

```

394

395

### AST Manipulation with Visitors

396

397

The visitor system allows efficient traversal and manipulation of grammar ASTs with type-safe node visiting.

398

399

```typescript { .api }

400

namespace compiler {

401

namespace visitor {

402

/**

403

* Build visitor function from node type handlers

404

* @param functions - Object mapping node types to visitor functions

405

* @returns Visitor function for AST traversal

406

*/

407

function build<F extends NodeTypes>(functions: F): Visitor<F>;

408

409

/**

410

* Visitor function interface

411

*/

412

interface Visitor<F extends NodeTypes> {

413

/**

414

* Visit AST node with appropriate handler

415

* @param node - AST node to visit

416

* @param args - Additional arguments for visitor

417

* @returns Result from node handler

418

*/

419

<T extends keyof NodeTypes>(

420

node: ast.Node<T>,

421

...args: any[]

422

): ReturnType<AnyFunction & F[T]>;

423

}

424

425

/**

426

* Node type visitor functions

427

*/

428

interface NodeTypes {

429

/** Visit grammar root - default: visit imports, initializers, rules */

430

grammar?(node: ast.Grammar, ...args: any[]): any;

431

/** Visit import statement - default: do nothing */

432

grammar_import?(node: ast.GrammarImport, ...args: any[]): any;

433

/** Visit top-level initializer - default: do nothing */

434

top_level_initializer?(node: ast.TopLevelInitializer, ...args: any[]): any;

435

/** Visit per-parse initializer - default: do nothing */

436

initializer?(node: ast.Initializer, ...args: any[]): any;

437

/** Visit rule - default: visit expression */

438

rule?(node: ast.Rule, ...args: any[]): any;

439

/** Visit named expression - default: visit expression */

440

named?(node: ast.Named, ...args: any[]): any;

441

/** Visit choice - default: visit all alternatives */

442

choice?(node: ast.Choice, ...args: any[]): any;

443

/** Visit action - default: visit expression */

444

action?(node: ast.Action, ...args: any[]): any;

445

/** Visit sequence - default: visit all elements */

446

sequence?(node: ast.Sequence, ...args: any[]): any;

447

/** Visit labeled expression - default: visit expression */

448

labeled?(node: ast.Labeled, ...args: any[]): any;

449

/** Visit text operator - default: visit expression */

450

text?(node: ast.Prefixed, ...args: any[]): any;

451

/** Visit positive lookahead - default: visit expression */

452

simple_and?(node: ast.Prefixed, ...args: any[]): any;

453

/** Visit negative lookahead - default: visit expression */

454

simple_not?(node: ast.Prefixed, ...args: any[]): any;

455

/** Visit optional - default: visit expression */

456

optional?(node: ast.Suffixed, ...args: any[]): any;

457

/** Visit zero-or-more - default: visit expression */

458

zero_or_more?(node: ast.Suffixed, ...args: any[]): any;

459

/** Visit one-or-more - default: visit expression */

460

one_or_more?(node: ast.Suffixed, ...args: any[]): any;

461

/** Visit repeated - default: visit delimiter then expression */

462

repeated?(node: ast.Repeated, ...args: any[]): any;

463

/** Visit group - default: visit expression */

464

group?(node: ast.Group, ...args: any[]): any;

465

/** Visit semantic AND predicate - default: do nothing */

466

semantic_and?(node: ast.SemanticPredicate, ...args: any[]): any;

467

/** Visit semantic NOT predicate - default: do nothing */

468

semantic_not?(node: ast.SemanticPredicate, ...args: any[]): any;

469

/** Visit rule reference - default: do nothing */

470

rule_ref?(node: ast.RuleReference, ...args: any[]): any;

471

/** Visit library reference - default: do nothing */

472

library_ref?(node: ast.LibraryReference, ...args: any[]): any;

473

/** Visit literal - default: do nothing */

474

literal?(node: ast.Literal, ...args: any[]): any;

475

/** Visit character class - default: do nothing */

476

class?(node: ast.CharacterClass, ...args: any[]): any;

477

/** Visit any-character - default: do nothing */

478

any?(node: ast.Any, ...args: any[]): any;

479

}

480

481

type AnyFunction = (...args: any[]) => any;

482

}

483

}

484

```

485

486

### Advanced Compilation Options

487

488

Extended options for controlling specific aspects of the compilation process.

489

490

```typescript { .api }

491

/**

492

* Stage name type

493

*/

494

type Stage = keyof Stages;

495

496

/**

497

* Diagnostic callback for compilation messages

498

*/

499

type DiagnosticCallback = (

500

stage: Stage,

501

message: string,

502

location?: LocationRange,

503

notes?: DiagnosticNote[]

504

) => void;

505

506

/**

507

* Parser dependencies mapping for module systems

508

*/

509

interface Dependencies {

510

[variable: string]: string;

511

}

512

513

/**

514

* Source output format types

515

*/

516

type SourceOutputs = "parser" | "source-and-map" | "source-with-inline-map" | "source" | "ast";

517

```

518

519

**Advanced Compilation Example:**

520

521

```typescript

522

import { parser, compiler, GrammarError } from "peggy";

523

524

try {

525

const ast = parser.parse(grammar, { reservedWords: [] });

526

527

// Custom compilation with detailed diagnostics

528

const result = compiler.compile(ast, compiler.passes, {

529

output: "source-and-map",

530

format: "es",

531

dependencies: {

532

"validator": "./validator.js"

533

},

534

grammarSource: "my-grammar.peggy",

535

cache: true,

536

trace: true,

537

allowedStartRules: ["*"], // All rules as start rules

538

error: (stage, message, location, notes) => {

539

console.error(`[${stage}] ERROR: ${message}`);

540

if (location) {

541

console.error(` at line ${location.start.line}, column ${location.start.column}`);

542

}

543

notes?.forEach(note => {

544

console.error(` note: ${note.message}`);

545

});

546

},

547

warning: (stage, message, location) => {

548

console.warn(`[${stage}] WARNING: ${message}`);

549

},

550

info: (stage, message) => {

551

console.log(`[${stage}] ${message}`);

552

}

553

});

554

555

if (typeof result === "string") {

556

console.log("Generated source code");

557

} else {

558

// SourceNode

559

const { code, map } = result.toStringWithSourceMap({

560

file: "generated-parser.js"

561

});

562

console.log("Generated code with source map");

563

}

564

565

} catch (error) {

566

if (error instanceof GrammarError) {

567

console.error("Compilation failed:");

568

error.problems.forEach(([severity, message, location]) => {

569

console.error(`${severity.toUpperCase()}: ${message}`);

570

});

571

}

572

}

573

```