import * as assert from 'assert'; import * as source from 'llparse-builder'; import { Frontend, node } from '../src/frontend'; import implementation from './fixtures/implementation'; import { Node } from './fixtures/implementation/node/base'; function checkNodes(f: Frontend, root: source.node.Node, expected: ReadonlyArray) { const fRoot = f.compile(root, []).root as Node; const out: string[] = []; fRoot.build(out); assert.deepStrictEqual(out, expected); return fRoot; } function checkResumptionTargets(f: Frontend, expected: ReadonlyArray) { const targets = Array.from(f.getResumptionTargets()).map((t) => { return t.ref.id.name; }); assert.deepStrictEqual(targets, expected); } describe('llparse-frontend', () => { let b: source.Builder; let f: Frontend; beforeEach(() => { b = new source.Builder(); f = new Frontend('llparse', implementation); }); it('should translate nodes to implementation', () => { const root = b.node('root'); root.match('ab', root); root.match('acd', root); root.match('efg', root); root.otherwise(b.error(123, 'hello')); checkNodes(f, root, [ '', '', '', '', '', ]); checkResumptionTargets(f, [ 'llparse__n_root', 'llparse__n_root_1', 'llparse__n_root_3', 'llparse__n_root_2', ]); }); it('should do peephole optimization', () => { const root = b.node('root'); const root1 = b.node('a'); const root2 = b.node('b'); const node1 = b.node('c'); const node2 = b.node('d'); root.otherwise(root1); root1.otherwise(root2); root2.skipTo(node1); node1.otherwise(node2); node2.otherwise(root); checkNodes(f, root, [ '', ]); checkResumptionTargets(f, [ 'llparse__n_b', ]); }); it('should generate proper resumption targets', () => { b.property('i64', 'counter'); const root = b.node('root'); const end = b.node('end'); const store = b.invoke(b.code.store('counter')); root.select({ a: 1, b: 2 }, store); root.otherwise(b.error(1, 'okay')); store.otherwise(end); end.match('ohai', root); end.match('paus', b.pause(1, 'paused').otherwise( b.pause(2, 'paused').otherwise(root))); end.otherwise(b.error(2, 'ohai')); checkNodes(f, root, [ '', '', '', '', '', '', '', '', '', ]); checkResumptionTargets(f, [ 'llparse__n_root', 'llparse__n_end', 'llparse__n_end_1', 'llparse__n_end_2', 'llparse__n_pause_1', ]); }); it('should translate Span code into Span', () => { const root = b.invoke(b.code.span('my_span')); root.otherwise(b.error(1, 'okay')); const fRoot = checkNodes(f, root, [ '', '', ]); assert((fRoot.ref as any).code instanceof implementation.code.Span); }); it('should translate overlapping matches', () => { const root = b.node('root'); root.match('ab', root); root.match('abc', root); root.otherwise(b.error(123, 'hello')); checkNodes(f, root, [ '', '', '', ]); checkResumptionTargets(f, [ 'llparse__n_root', 'llparse__n_root_1', ]); }); it('should translate overlapping matches with values', () => { const root = b.node('root'); const store = b.invoke(b.code.store('counter')); root.select({ ab: 1, abc: 2, }, store); store.otherwise(root); root.otherwise(b.error(123, 'hello')); checkNodes(f, root, [ '', '', '', '', ]); checkResumptionTargets(f, [ 'llparse__n_root', 'llparse__n_root_1', ]); }); });