or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-tool.mdcompiler-system.mdgrammar-parsing.mdindex.mdparser-generation.mdutility-modules.md

compiler-system.mddocs/

0

# Compiler System

1

2

Multi-pass compiler architecture for transforming grammar ASTs into executable parser code with validation, optimization, and code generation capabilities.

3

4

## Capabilities

5

6

### Main Compiler Interface

7

8

Compiles grammar ASTs into executable parsers through configurable compilation passes.

9

10

```javascript { .api }

11

/**

12

* Compiler module interface

13

*/

14

const compiler = {

15

/**

16

* Compile grammar AST into executable parser

17

* @param ast - Grammar AST from parser

18

* @param passes - Compilation passes organized by stage

19

* @param options - Compilation options

20

* @returns Generated parser object or source code string

21

* @throws {GrammarError} If AST contains semantic errors

22

*/

23

compile: function(ast, passes, options),

24

25

/**

26

* AST visitor builder for traversing syntax trees

27

*/

28

visitor: {

29

build: function(functions)

30

},

31

32

/**

33

* Built-in compilation passes organized by stage

34

*/

35

passes: {

36

check: Object, // Validation passes

37

transform: Object, // AST transformation passes

38

generate: Object // Code generation passes

39

}

40

};

41

```

42

43

**Usage Examples:**

44

45

```javascript

46

const peg = require("pegjs");

47

48

// Parse grammar into AST

49

const ast = peg.parser.parse("start = 'hello'");

50

51

// Compile with default passes

52

const parser = peg.compiler.compile(

53

ast,

54

peg.compiler.passes,

55

{ output: "parser" }

56

);

57

58

// Compile with custom pass configuration

59

const customPasses = {

60

check: [

61

peg.compiler.passes.check.reportUndefinedRules,

62

peg.compiler.passes.check.reportDuplicateRules

63

],

64

transform: [

65

peg.compiler.passes.transform.removeProxyRules

66

],

67

generate: [

68

peg.compiler.passes.generate.generateBytecode,

69

peg.compiler.passes.generate.generateJS

70

]

71

};

72

73

const source = peg.compiler.compile(ast, customPasses, {

74

output: "source",

75

format: "commonjs"

76

});

77

```

78

79

### Compilation Options

80

81

Configuration options for the compilation process.

82

83

```javascript { .api }

84

/**

85

* Compilation options interface

86

*/

87

interface CompileOptions {

88

/** Rules parser can start from (default: [first rule]) */

89

allowedStartRules?: string[];

90

91

/** Enable result caching (default: false) */

92

cache?: boolean;

93

94

/** Module dependencies map (default: {}) */

95

dependencies?: { [key: string]: string };

96

97

/** Global variable name for globals/umd format (default: null) */

98

exportVar?: string;

99

100

/** Output format (default: "bare") */

101

format?: "amd" | "bare" | "commonjs" | "globals" | "umd";

102

103

/** Optimization target (default: "speed") */

104

optimize?: "speed" | "size";

105

106

/** Output type (default: "parser") */

107

output?: "parser" | "source";

108

109

/** Enable tracing (default: false) */

110

trace?: boolean;

111

}

112

```

113

114

## Compilation Passes

115

116

### Check Passes

117

118

Validation passes that detect semantic errors in grammar ASTs.

119

120

```javascript { .api }

121

/**

122

* Validation passes for semantic analysis

123

*/

124

const checkPasses = {

125

/**

126

* Report references to undefined rules

127

* @param ast - Grammar AST to analyze

128

* @param options - Compilation options

129

* @throws {GrammarError} If undefined rules found

130

*/

131

reportUndefinedRules: function(ast, options),

132

133

/**

134

* Report duplicate rule definitions

135

* @param ast - Grammar AST to analyze

136

* @param options - Compilation options

137

* @throws {GrammarError} If duplicate rules found

138

*/

139

reportDuplicateRules: function(ast, options),

140

141

/**

142

* Report duplicate labels within rules

143

* @param ast - Grammar AST to analyze

144

* @param options - Compilation options

145

* @throws {GrammarError} If duplicate labels found

146

*/

147

reportDuplicateLabels: function(ast, options),

148

149

/**

150

* Report infinite recursion patterns

151

* @param ast - Grammar AST to analyze

152

* @param options - Compilation options

153

* @throws {GrammarError} If infinite recursion detected

154

*/

155

reportInfiniteRecursion: function(ast, options),

156

157

/**

158

* Report infinite repetition patterns

159

* @param ast - Grammar AST to analyze

160

* @param options - Compilation options

161

* @throws {GrammarError} If infinite repetition detected

162

*/

163

reportInfiniteRepetition: function(ast, options)

164

};

165

```

166

167

**Check Pass Example:**

168

169

```javascript

170

// These passes will throw GrammarError if issues are found

171

try {

172

peg.compiler.passes.check.reportUndefinedRules(ast, options);

173

peg.compiler.passes.check.reportDuplicateRules(ast, options);

174

} catch (error) {

175

if (error.name === "GrammarError") {

176

console.error("Grammar validation error:", error.message);

177

}

178

}

179

```

180

181

### Transform Passes

182

183

AST transformation passes that optimize or modify the syntax tree.

184

185

```javascript { .api }

186

/**

187

* AST transformation passes

188

*/

189

const transformPasses = {

190

/**

191

* Remove proxy rules that just forward to other rules

192

* Optimizes the AST by eliminating unnecessary indirection

193

* @param ast - Grammar AST to transform

194

* @param options - Compilation options

195

*/

196

removeProxyRules: function(ast, options)

197

};

198

```

199

200

**Transform Pass Example:**

201

202

```javascript

203

// Grammar with proxy rule:

204

// start = expression

205

// expression = number

206

// number = [0-9]+

207

208

// After removeProxyRules:

209

// start = number

210

// number = [0-9]+

211

// (expression rule removed as it just forwards to number)

212

213

peg.compiler.passes.transform.removeProxyRules(ast, options);

214

```

215

216

### Generate Passes

217

218

Code generation passes that produce executable parser code.

219

220

```javascript { .api }

221

/**

222

* Code generation passes

223

*/

224

const generatePasses = {

225

/**

226

* Generate intermediate bytecode representation

227

* First stage of code generation process

228

* @param ast - Grammar AST to compile

229

* @param options - Compilation options

230

*/

231

generateBytecode: function(ast, options),

232

233

/**

234

* Generate final JavaScript parser code

235

* Second stage that converts bytecode to JavaScript

236

* @param ast - Grammar AST with bytecode

237

* @param options - Compilation options

238

*/

239

generateJS: function(ast, options)

240

};

241

```

242

243

**Generate Pass Example:**

244

245

```javascript

246

// Two-stage generation process

247

peg.compiler.passes.generate.generateBytecode(ast, options);

248

peg.compiler.passes.generate.generateJS(ast, options);

249

250

// After generation, ast.code contains the JavaScript parser source

251

console.log(ast.code); // Generated parser code

252

```

253

254

## AST Visitor System

255

256

### Visitor Builder

257

258

Creates visitor functions for traversing and manipulating ASTs.

259

260

```javascript { .api }

261

/**

262

* AST visitor builder

263

*/

264

const visitor = {

265

/**

266

* Build visitor function from handler map

267

* @param functions - Map of node types to handler functions

268

* @returns Visitor function for traversing ASTs

269

*/

270

build: function(functions): (node: ASTNode) => any

271

};

272

273

/**

274

* Visitor function interface

275

*/

276

interface VisitorFunction {

277

(node: ASTNode, ...extraArgs: any[]): any;

278

}

279

280

/**

281

* Handler function map for different node types

282

*/

283

interface VisitorHandlers {

284

grammar?: (node: GrammarNode, ...args: any[]) => any;

285

initializer?: (node: InitializerNode, ...args: any[]) => any;

286

rule?: (node: RuleNode, ...args: any[]) => any;

287

choice?: (node: ChoiceNode, ...args: any[]) => any;

288

sequence?: (node: SequenceNode, ...args: any[]) => any;

289

labeled?: (node: LabeledNode, ...args: any[]) => any;

290

action?: (node: ActionNode, ...args: any[]) => any;

291

optional?: (node: OptionalNode, ...args: any[]) => any;

292

zero_or_more?: (node: ZeroOrMoreNode, ...args: any[]) => any;

293

one_or_more?: (node: OneOrMoreNode, ...args: any[]) => any;

294

simple_and?: (node: SimpleAndNode, ...args: any[]) => any;

295

simple_not?: (node: SimpleNotNode, ...args: any[]) => any;

296

semantic_and?: (node: SemanticAndNode, ...args: any[]) => any;

297

semantic_not?: (node: SemanticNotNode, ...args: any[]) => any;

298

rule_ref?: (node: RuleRefNode, ...args: any[]) => any;

299

literal?: (node: LiteralNode, ...args: any[]) => any;

300

class?: (node: ClassNode, ...args: any[]) => any;

301

any?: (node: AnyNode, ...args: any[]) => any;

302

text?: (node: TextNode, ...args: any[]) => any;

303

named?: (node: NamedNode, ...args: any[]) => any;

304

group?: (node: GroupNode, ...args: any[]) => any;

305

}

306

```

307

308

**Visitor Usage Examples:**

309

310

```javascript

311

// Create a visitor that counts rule references

312

const countRefs = peg.compiler.visitor.build({

313

rule_ref: function(node, counts) {

314

counts[node.name] = (counts[node.name] || 0) + 1;

315

}

316

});

317

318

const refCounts = {};

319

countRefs(ast, refCounts);

320

console.log(refCounts); // { ruleName: count, ... }

321

322

// Create a visitor that collects all string literals

323

const collectLiterals = peg.compiler.visitor.build({

324

literal: function(node, literals) {

325

literals.push(node.value);

326

}

327

});

328

329

const literals = [];

330

collectLiterals(ast, literals);

331

console.log(literals); // ["string1", "string2", ...]

332

333

// Create a visitor that transforms nodes

334

const transformRefs = peg.compiler.visitor.build({

335

rule_ref: function(node) {

336

// Transform rule references to uppercase

337

node.name = node.name.toUpperCase();

338

}

339

});

340

341

transformRefs(ast); // Modifies AST in place

342

```

343

344

### Default Visitor Behavior

345

346

The visitor builder provides default traversal behavior for all node types:

347

348

```javascript

349

// Default handlers automatically traverse child nodes

350

// You only need to override specific node types you want to handle

351

352

const visitor = peg.compiler.visitor.build({

353

// Only handle literals, all other nodes traversed automatically

354

literal: function(node) {

355

console.log("Found literal:", node.value);

356

}

357

});

358

```

359

360

## Custom Compilation Passes

361

362

### Creating Custom Passes

363

364

You can create custom compilation passes for specialized validation or transformation:

365

366

```javascript

367

// Custom validation pass

368

function reportLongRuleNames(ast, options) {

369

const visitor = peg.compiler.visitor.build({

370

rule: function(node) {

371

if (node.name.length > 20) {

372

throw new peg.GrammarError(

373

`Rule name too long: ${node.name}`,

374

node.location

375

);

376

}

377

}

378

});

379

380

visitor(ast);

381

}

382

383

// Custom transformation pass

384

function prefixRuleNames(ast, options) {

385

const prefix = options.rulePrefix || "rule_";

386

387

const visitor = peg.compiler.visitor.build({

388

rule: function(node) {

389

if (!node.name.startsWith(prefix)) {

390

node.name = prefix + node.name;

391

}

392

},

393

rule_ref: function(node) {

394

if (!node.name.startsWith(prefix)) {

395

node.name = prefix + node.name;

396

}

397

}

398

});

399

400

visitor(ast);

401

}

402

403

// Use custom passes

404

const customPasses = {

405

check: [

406

peg.compiler.passes.check.reportUndefinedRules,

407

reportLongRuleNames // Custom validation

408

],

409

transform: [

410

prefixRuleNames, // Custom transformation

411

peg.compiler.passes.transform.removeProxyRules

412

],

413

generate: [

414

peg.compiler.passes.generate.generateBytecode,

415

peg.compiler.passes.generate.generateJS

416

]

417

};

418

419

const parser = peg.compiler.compile(ast, customPasses, {

420

rulePrefix: "my_",

421

output: "parser"

422

});

423

```