diff --git a/src/runtime/javascript/index.ts b/src/runtime/javascript/index.ts index 8fe50db96..702b666c3 100644 --- a/src/runtime/javascript/index.ts +++ b/src/runtime/javascript/index.ts @@ -138,12 +138,22 @@ function handleError (err: StructObject): void { } } -function PgfText_AsString (txtPtr: Pointer) { +function PgfText_AsString (txtPtr: Pointer): string { const txtSize = txtPtr.deref().size const charPtr = ref.reinterpret(txtPtr, txtSize, ref.types.size_t.size) return charPtr.toString('utf8') } +function PgfText_FromString (str: string): Pointer { + const strbuf = Buffer.from(str, 'utf8') + const size = strbuf.length // size in bytes, not chars + const sizebuf = ref.alloc(ref.types.size_t, size) + const txtbuf = Buffer.alloc(ref.types.size_t.size + size + 1) + sizebuf.copy(txtbuf, 0, 0) + strbuf.copy(txtbuf, ref.types.size_t.size, 0) + return txtbuf as Pointer +} + // ---------------------------------------------------------------------------- // PGF grammar object @@ -215,20 +225,31 @@ function bootNGF (pgf_path: string, ngf_path: string): PGFGrammar { return new PGFGrammar(db, rev) } +function readNGF (path: string): PGFGrammar { + const rev = ref.alloc(PgfRevisionPtr) + const err = new PgfExn + const db = runtime.pgf_read_ngf(path, rev, err.ref()) + handleError(err) + return new PGFGrammar(db, rev) +} + +function newNGF (abstract_name: string, path?: string): PGFGrammar { + const absname = PgfText_FromString(abstract_name) + const fpath = path != null ? path : null + const rev = ref.alloc(PgfRevisionPtr) + const err = new PgfExn + const db = runtime.pgf_new_ngf(absname, fpath, rev, err.ref()) + handleError(err) + return new PGFGrammar(db, rev) +} + // ---------------------------------------------------------------------------- // Exposed library API export default { PGFError, readPGF, - bootNGF + bootNGF, + readNGF, + newNGF } - -// ---------------------------------------------------------------------------- -// Quick testing - -// const gr = readPGF('../haskell/tests/basic.pgf') -// console.log(gr) -// console.log(gr.getAbstractName()) -// console.log(gr.getCategories()) -// console.log(gr.getFunctions()) diff --git a/src/runtime/javascript/tests/basic.test.ts b/src/runtime/javascript/tests/basic.test.ts index 050b59036..f975b1d24 100644 --- a/src/runtime/javascript/tests/basic.test.ts +++ b/src/runtime/javascript/tests/basic.test.ts @@ -1,6 +1,8 @@ import PGF, { PGFGrammar } from '../index' import fs from 'fs' +// ---------------------------------------------------------------------------- + describe('readPGF', () => { test('valid', () => { PGF.readPGF('../haskell/tests/basic.pgf') @@ -18,13 +20,21 @@ describe('readPGF', () => { }).toThrow(PGF.PGFError) }) - // test('NGF', () => { - // expect(() => { - // PGF.readPGF('basic.ngf') - // }).toThrow(PGF.PGFError) - // }) + test('NGF', () => { + try { + fs.unlinkSync('./basic.ngf') + } catch { + // empty + } + PGF.bootNGF('../haskell/tests/basic.pgf', './basic.ngf') + expect(() => { + PGF.readPGF('./basic.ngf') + }).toThrow(PGF.PGFError) + }) }) +// ---------------------------------------------------------------------------- + describe('bootNGF', () => { beforeAll(() => { try { @@ -63,6 +73,71 @@ describe('bootNGF', () => { }) }) +// ---------------------------------------------------------------------------- + +describe('readNGF', () => { + // beforeAll(() => { + // try { + // fs.unlinkSync('./basic.ngf') + // } catch { + // // empty + // } + // }) + + test('valid', () => { + const gr = PGF.readNGF('./basic.ngf') + expect(gr.getCategories().length).toBeGreaterThan(0) + }) + + test('non-existent', () => { + expect(() => { + PGF.readNGF('./abc.ngf') + }).toThrow(Error) + }) + + test('GF', () => { + expect(() => { + PGF.readNGF('../haskell/tests/basic.gf') + }).toThrow(PGF.PGFError) + }) + + test('PGF', () => { + expect(() => { + PGF.readNGF('../haskell/tests/basic.pgf') + }).toThrow(PGF.PGFError) + }) +}) + +// ---------------------------------------------------------------------------- + +describe('newNGF', () => { + beforeAll(() => { + try { + fs.unlinkSync('./empty.ngf') + } catch { + // empty + } + }) + + test('file', () => { + const gr = PGF.newNGF('empty', './empty.ngf') + expect(gr.getCategories().length).toBe(0) + }) + + test('memory', () => { + const gr = PGF.newNGF('empty') + expect(gr.getCategories().length).toBe(0) + }) + + test('existing', () => { + expect(() => { + PGF.newNGF('empty', './basic.ngf') + }).toThrow(Error) + }) +}) + +// ---------------------------------------------------------------------------- + describe('abstract syntax', () => { let gr: PGFGrammar