kach / nearley

πŸ“œπŸ”œπŸŒ² Simple, fast, powerful parser toolkit for JavaScript.
https://nearley.js.org
MIT License
3.57k stars 231 forks source link

Feature - Support runtime grammar compilation for unit-testing. #647

Open TekuConcept opened 3 months ago

TekuConcept commented 3 months ago

When running unit tests against grammar definitions, I currently do the following:

async function compileGrammarText(text: string) {
    return new Promise<CompiledRules>((res, rej) => {
        const proc = exec('npx nearleyc -q', (err, stdout, stderr) => {
            if (err) rej(stderr)

            const window = { grammar: null }
            Function("window", stdout)(window)
            res(window.grammar)
        })

        proc.stdin.write(text)
        proc.stdin.end()
    })
}

describe('DEFINITION_NAME', () => {
    let parser: Parser
    let initState: any

    before(async () => {
        const grammar = await Utils.compileGrammarText(`
            @include "${__dirname}/grammar.ne"
            input -> DEFINITION_NAME {% id %}
        `)
        parser = new Parser(Grammar.fromCompiled(grammar))
        initState = parser.save()
    })

    beforeEach(() => parser.restore(initState))

    tests.forEach(test => {
        it(`should parse "${test.value}"`, () => {
            parser.feed(test.value)
            expect(parser.results).to.deep.equal(test.expected)
        })
    })
})

For 500 or so unit tests, this can take about 30 seconds or more to run - most of that time being spent piping data to and from nearleyc. If/when I get some time, I'd like to abstract the compiler logic from nearleyc's IO and expose it as part of the library's API.