CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nearley

Simple, fast, powerful parser toolkit for JavaScript using the Earley parsing algorithm

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

text-generation.mddocs/

Text Generation

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

Capabilities

Unparse Function

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

/**
 * Generate random text from a compiled grammar or Grammar instance
 * @param grammar - Compiled grammar object (from nearleyc) or Grammar instance
 * @param start - Start symbol name (optional, uses grammar default)
 * @param depth - Maximum recursion depth (optional, null for unbounded)
 * @returns Random text string matching the grammar
 */
function Unparse(grammar: object | Grammar, start?: string, depth?: number | null): string;

Usage Examples:

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

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

// Generate random arithmetic expressions
const randomExpr1 = Unparse(grammar);
console.log("Random expression:", randomExpr1);
// Example output: "42 + 17 * 3"

// Generate with specific start symbol
const randomExpr2 = Unparse(grammar, "factor");
console.log("Random factor:", randomExpr2);
// Example output: "123"

// Generate with depth limit to avoid infinite recursion
const boundedExpr = Unparse(grammar, "expr", 5);
console.log("Bounded expression:", boundedExpr);
// Example output: "8 + 2" (shorter due to depth limit)

Unbounded Generation

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

/**
 * Generate unbounded random text (use with caution)
 * @param grammar - Grammar instance or compiled grammar object
 * @param start - Start symbol name
 * @returns Random text string (may be very long or not terminate)
 */
function genRandom(grammar: Grammar, start: string): string;

Usage Examples:

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

// Use only with grammars that naturally terminate
const terminalGrammar = require("./finite-grammar.js");

try {
  // Generate without limits (risky with recursive grammars)
  const result = genRandom(terminalGrammar, "sentence");
  console.log("Generated:", result);
} catch (error) {
  console.error("Generation failed:", error.message);
}

Bounded Generation

Generate text with explicit depth bounds to guarantee termination.

/**
 * Generate bounded random text with depth limit
 * @param grammar - Grammar instance or compiled grammar object
 * @param start - Start symbol name  
 * @param depth - Maximum recursion depth
 * @returns Random text string within depth bounds
 */
function genBounded(grammar: Grammar, start: string, depth: number): string;

Usage Examples:

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

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

// Generate with various depth limits
for (let depth = 1; depth <= 5; depth++) {
  const result = genBounded(grammar, "expr", depth);
  console.log(`Depth ${depth}: ${result}`);
}

// Example output:
// Depth 1: "x"
// Depth 2: "x + y" 
// Depth 3: "(x + y) * z"
// Depth 4: "((x + y) * z) - (a + b)"
// Depth 5: "(((x + y) * z) - (a + b)) / ((c * d) + e)"

Testing and Fuzzing

Use text generation for systematic testing of parsers.

Usage Examples:

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

// Test parser with generated inputs
function fuzzTestParser(grammarFile, numTests = 100) {
  const compiledGrammar = require(grammarFile);
  const grammar = nearley.Grammar.fromCompiled(compiledGrammar);
  
  let passed = 0;
  let failed = 0;
  
  for (let i = 0; i < numTests; i++) {
    // Generate random input
    const input = Unparse(compiledGrammar, null, 10);
    
    try {
      // Test if parser can parse generated input
      const parser = new nearley.Parser(grammar);
      parser.feed(input);
      
      if (parser.results.length > 0) {
        passed++;
        console.log(`✓ Test ${i + 1}: "${input}"`);
      } else {
        failed++;
        console.log(`✗ Test ${i + 1}: No parse for "${input}"`);
      }
    } catch (error) {
      failed++;
      console.log(`✗ Test ${i + 1}: Parse error for "${input}": ${error.message}`);
    }
  }
  
  console.log(`\nResults: ${passed} passed, ${failed} failed`);
  return { passed, failed };
}

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

Example Generation

Generate example inputs for documentation and tutorials.

Usage Examples:

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

// Generate examples for documentation
function generateExamples(grammarFile, count = 10) {
  const grammar = require(grammarFile);
  const examples = new Set(); // Use Set to avoid duplicates
  
  // Generate unique examples
  while (examples.size < count) {
    const example = Unparse(grammar, null, 8);
    examples.add(example);
  }
  
  return Array.from(examples).sort();
}

// Generate examples for different complexity levels
function generateTieredExamples(grammarFile) {
  const grammar = require(grammarFile);
  
  const tiers = {
    simple: [],
    medium: [],
    complex: []
  };
  
  // Generate examples at different depth levels
  for (let i = 0; i < 20; i++) {
    tiers.simple.push(Unparse(grammar, null, 2));
    tiers.medium.push(Unparse(grammar, null, 5));
    tiers.complex.push(Unparse(grammar, null, 10));
  }
  
  // Remove duplicates and sort
  Object.keys(tiers).forEach(tier => {
    tiers[tier] = [...new Set(tiers[tier])].sort();
  });
  
  return tiers;
}

// Generate examples for arithmetic grammar
const examples = generateTieredExamples("./arithmetic-grammar.js");
console.log("Simple examples:", examples.simple.slice(0, 5));
console.log("Medium examples:", examples.medium.slice(0, 5));
console.log("Complex examples:", examples.complex.slice(0, 5));

Working with Lexer-based Grammars

Generate text for grammars that use external lexers like moo.

Usage Examples:

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

// For grammars with lexers, ensure the generated text produces valid tokens
function generateWithLexer(grammarFile) {
  const compiledGrammar = require(grammarFile);
  
  // Generate text
  const generated = Unparse(compiledGrammar, null, 6);
  console.log("Generated text:", generated);
  
  // Verify it can be lexed (if lexer is available)
  if (compiledGrammar.Lexer) {
    const lexer = compiledGrammar.Lexer;
    lexer.reset(generated);
    
    console.log("Tokens:");
    let token;
    while ((token = lexer.next())) {
      console.log(`  ${token.type}: "${token.value}"`);
    }
  }
  
  return generated;
}

// Test with a moo-based grammar
generateWithLexer("./lexer-grammar.js");

Debugging Grammar Coverage

Use generation to test coverage of grammar rules.

Usage Examples:

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

// Test which grammar rules are being exercised
function testGrammarCoverage(grammarFile, numTests = 1000) {
  const grammar = require(grammarFile);
  const ruleCounts = new Map();
  
  // Track rule usage during generation
  for (let i = 0; i < numTests; i++) {
    const generated = Unparse(grammar, null, 8);
    
    // Parse the generated text to see which rules fired
    const nearley = require("nearley");
    const grammarObj = nearley.Grammar.fromCompiled(grammar);
    const parser = new nearley.Parser(grammarObj);
    
    try {
      parser.feed(generated);
      
      // Analyze parse table to count rule usage
      if (parser.results.length > 0) {
        // This is a simplified analysis - actual implementation
        // would need to traverse parse trees to count rule usage
        console.log(`Generated: "${generated}"`);
      }
    } catch (error) {
      // Skip failed generations
    }
  }
  
  return ruleCounts;
}

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

docs

cli-tools.md

core-parsing.md

grammar-management.md

index.md

stream-processing.md

text-generation.md

tile.json