or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-tools.mdcore-parsing.mdgrammar-management.mdindex.mdstream-processing.mdtext-generation.md

text-generation.mddocs/

0

# Text Generation

1

2

Random text generation from grammars for testing, fuzzing, and example generation.

3

4

## Capabilities

5

6

### Unparse Function

7

8

Generate random text that matches a given grammar, useful for testing parsers and creating example inputs.

9

10

```javascript { .api }

11

/**

12

* Generate random text from a compiled grammar or Grammar instance

13

* @param grammar - Compiled grammar object (from nearleyc) or Grammar instance

14

* @param start - Start symbol name (optional, uses grammar default)

15

* @param depth - Maximum recursion depth (optional, null for unbounded)

16

* @returns Random text string matching the grammar

17

*/

18

function Unparse(grammar: object | Grammar, start?: string, depth?: number | null): string;

19

```

20

21

**Usage Examples:**

22

23

```javascript

24

const Unparse = require("nearley/lib/unparse");

25

26

// Load compiled grammar

27

const grammar = require("./arithmetic-grammar.js");

28

29

// Generate random arithmetic expressions

30

const randomExpr1 = Unparse(grammar);

31

console.log("Random expression:", randomExpr1);

32

// Example output: "42 + 17 * 3"

33

34

// Generate with specific start symbol

35

const randomExpr2 = Unparse(grammar, "factor");

36

console.log("Random factor:", randomExpr2);

37

// Example output: "123"

38

39

// Generate with depth limit to avoid infinite recursion

40

const boundedExpr = Unparse(grammar, "expr", 5);

41

console.log("Bounded expression:", boundedExpr);

42

// Example output: "8 + 2" (shorter due to depth limit)

43

```

44

45

### Unbounded Generation

46

47

Generate text without depth restrictions (may not terminate for recursive grammars).

48

49

```javascript { .api }

50

/**

51

* Generate unbounded random text (use with caution)

52

* @param grammar - Grammar instance or compiled grammar object

53

* @param start - Start symbol name

54

* @returns Random text string (may be very long or not terminate)

55

*/

56

function genRandom(grammar: Grammar, start: string): string;

57

```

58

59

**Usage Examples:**

60

61

```javascript

62

const { genRandom } = require("nearley/lib/unparse");

63

64

// Use only with grammars that naturally terminate

65

const terminalGrammar = require("./finite-grammar.js");

66

67

try {

68

// Generate without limits (risky with recursive grammars)

69

const result = genRandom(terminalGrammar, "sentence");

70

console.log("Generated:", result);

71

} catch (error) {

72

console.error("Generation failed:", error.message);

73

}

74

```

75

76

### Bounded Generation

77

78

Generate text with explicit depth bounds to guarantee termination.

79

80

```javascript { .api }

81

/**

82

* Generate bounded random text with depth limit

83

* @param grammar - Grammar instance or compiled grammar object

84

* @param start - Start symbol name

85

* @param depth - Maximum recursion depth

86

* @returns Random text string within depth bounds

87

*/

88

function genBounded(grammar: Grammar, start: string, depth: number): string;

89

```

90

91

**Usage Examples:**

92

93

```javascript

94

const { genBounded } = require("nearley/lib/unparse");

95

96

const grammar = require("./recursive-grammar.js");

97

98

// Generate with various depth limits

99

for (let depth = 1; depth <= 5; depth++) {

100

const result = genBounded(grammar, "expr", depth);

101

console.log(`Depth ${depth}: ${result}`);

102

}

103

104

// Example output:

105

// Depth 1: "x"

106

// Depth 2: "x + y"

107

// Depth 3: "(x + y) * z"

108

// Depth 4: "((x + y) * z) - (a + b)"

109

// Depth 5: "(((x + y) * z) - (a + b)) / ((c * d) + e)"

110

```

111

112

### Testing and Fuzzing

113

114

Use text generation for systematic testing of parsers.

115

116

**Usage Examples:**

117

118

```javascript

119

const nearley = require("nearley");

120

const Unparse = require("nearley/lib/unparse");

121

122

// Test parser with generated inputs

123

function fuzzTestParser(grammarFile, numTests = 100) {

124

const compiledGrammar = require(grammarFile);

125

const grammar = nearley.Grammar.fromCompiled(compiledGrammar);

126

127

let passed = 0;

128

let failed = 0;

129

130

for (let i = 0; i < numTests; i++) {

131

// Generate random input

132

const input = Unparse(compiledGrammar, null, 10);

133

134

try {

135

// Test if parser can parse generated input

136

const parser = new nearley.Parser(grammar);

137

parser.feed(input);

138

139

if (parser.results.length > 0) {

140

passed++;

141

console.log(`✓ Test ${i + 1}: "${input}"`);

142

} else {

143

failed++;

144

console.log(`✗ Test ${i + 1}: No parse for "${input}"`);

145

}

146

} catch (error) {

147

failed++;

148

console.log(`✗ Test ${i + 1}: Parse error for "${input}": ${error.message}`);

149

}

150

}

151

152

console.log(`\nResults: ${passed} passed, ${failed} failed`);

153

return { passed, failed };

154

}

155

156

// Run fuzz test

157

fuzzTestParser("./json-grammar.js", 50);

158

```

159

160

### Example Generation

161

162

Generate example inputs for documentation and tutorials.

163

164

**Usage Examples:**

165

166

```javascript

167

const Unparse = require("nearley/lib/unparse");

168

169

// Generate examples for documentation

170

function generateExamples(grammarFile, count = 10) {

171

const grammar = require(grammarFile);

172

const examples = new Set(); // Use Set to avoid duplicates

173

174

// Generate unique examples

175

while (examples.size < count) {

176

const example = Unparse(grammar, null, 8);

177

examples.add(example);

178

}

179

180

return Array.from(examples).sort();

181

}

182

183

// Generate examples for different complexity levels

184

function generateTieredExamples(grammarFile) {

185

const grammar = require(grammarFile);

186

187

const tiers = {

188

simple: [],

189

medium: [],

190

complex: []

191

};

192

193

// Generate examples at different depth levels

194

for (let i = 0; i < 20; i++) {

195

tiers.simple.push(Unparse(grammar, null, 2));

196

tiers.medium.push(Unparse(grammar, null, 5));

197

tiers.complex.push(Unparse(grammar, null, 10));

198

}

199

200

// Remove duplicates and sort

201

Object.keys(tiers).forEach(tier => {

202

tiers[tier] = [...new Set(tiers[tier])].sort();

203

});

204

205

return tiers;

206

}

207

208

// Generate examples for arithmetic grammar

209

const examples = generateTieredExamples("./arithmetic-grammar.js");

210

console.log("Simple examples:", examples.simple.slice(0, 5));

211

console.log("Medium examples:", examples.medium.slice(0, 5));

212

console.log("Complex examples:", examples.complex.slice(0, 5));

213

```

214

215

### Working with Lexer-based Grammars

216

217

Generate text for grammars that use external lexers like moo.

218

219

**Usage Examples:**

220

221

```javascript

222

const Unparse = require("nearley/lib/unparse");

223

const moo = require("moo");

224

225

// For grammars with lexers, ensure the generated text produces valid tokens

226

function generateWithLexer(grammarFile) {

227

const compiledGrammar = require(grammarFile);

228

229

// Generate text

230

const generated = Unparse(compiledGrammar, null, 6);

231

console.log("Generated text:", generated);

232

233

// Verify it can be lexed (if lexer is available)

234

if (compiledGrammar.Lexer) {

235

const lexer = compiledGrammar.Lexer;

236

lexer.reset(generated);

237

238

console.log("Tokens:");

239

let token;

240

while ((token = lexer.next())) {

241

console.log(` ${token.type}: "${token.value}"`);

242

}

243

}

244

245

return generated;

246

}

247

248

// Test with a moo-based grammar

249

generateWithLexer("./lexer-grammar.js");

250

```

251

252

### Debugging Grammar Coverage

253

254

Use generation to test coverage of grammar rules.

255

256

**Usage Examples:**

257

258

```javascript

259

const Unparse = require("nearley/lib/unparse");

260

261

// Test which grammar rules are being exercised

262

function testGrammarCoverage(grammarFile, numTests = 1000) {

263

const grammar = require(grammarFile);

264

const ruleCounts = new Map();

265

266

// Track rule usage during generation

267

for (let i = 0; i < numTests; i++) {

268

const generated = Unparse(grammar, null, 8);

269

270

// Parse the generated text to see which rules fired

271

const nearley = require("nearley");

272

const grammarObj = nearley.Grammar.fromCompiled(grammar);

273

const parser = new nearley.Parser(grammarObj);

274

275

try {

276

parser.feed(generated);

277

278

// Analyze parse table to count rule usage

279

if (parser.results.length > 0) {

280

// This is a simplified analysis - actual implementation

281

// would need to traverse parse trees to count rule usage

282

console.log(`Generated: "${generated}"`);

283

}

284

} catch (error) {

285

// Skip failed generations

286

}

287

}

288

289

return ruleCounts;

290

}

291

292

// Analyze grammar coverage

293

testGrammarCoverage("./my-grammar.js", 100);

294

```