/* eslint-disable @typescript-eslint/naming-convention */ import errno from './errno' import { Type, mkType, Hypo, mkHypo, mkDepHypo, mkImplHypo, Expr, ExprAbs, ExprApp, ExprLit, ExprMeta, ExprFun, ExprVar, ExprTyped, ExprImplArg, Literal } from './expr' import { voidPtr, PgfRevisionPtr, PgfItorPtr, PgfTextPtr, PgfExn, PgfExnPtr, PgfText_AsString, PgfText_FromString, runtime, unmarshaller } from './ffi' import ffi from 'ffi-napi' import ref, { Pointer } from 'ref-napi' import { StructObject } from 'ref-struct-di' // ---------------------------------------------------------------------------- // TypeScript Types interface PgfExnType { type: number code: number msg: string | null } class PGFError extends Error { constructor (message: string) { super(message) // https://stackoverflow.com/a/65243177/98600 Object.setPrototypeOf(this, PGFError.prototype) } } // ---------------------------------------------------------------------------- // Helpers function handleError (err: StructObject): void { switch (err.type) { // PGF_EXN_NONE case 0: return // PGF_EXN_SYSTEM_ERROR case 1: { const desc = errno.lookup(err.code) throw new Error(`${desc as string}: ${err.msg as string}`) } // PGF_EXN_PGF_ERROR case 2: throw new PGFError(err.msg as string) // PGF_EXN_OTHER_ERROR case 3: throw new Error(err.msg as string) default: throw new Error(`unknown error type: ${err.type}`) } } // ---------------------------------------------------------------------------- // PGF grammar object class PGFGrammar { readonly db: Pointer readonly revision: Pointer constructor (db: Pointer, revision: Pointer) { this.db = db this.revision = revision } // NB the library user is responsible for calling this release (): void { runtime.pgf_free_revision(this.db, this.revision.deref()) } getAbstractName (): string { const err = new PgfExn() const txt = runtime.pgf_abstract_name(this.db, this.revision.deref(), err.ref()) handleError(err) return PgfText_AsString(txt) } getCategories (): string[] { const cats: string[] = [] const callback = ffi.Callback(ref.types.void, [PgfItorPtr, PgfTextPtr, voidPtr, PgfExnPtr], function (self: Pointer, key: Pointer, value: Pointer, err: Pointer) { const k = PgfText_AsString(key) cats.push(k) }) const err = new PgfExn() runtime.pgf_iter_categories(this.db, this.revision.deref(), callback.ref() as Pointer, err.ref()) handleError(err) return cats } getFunctions (): string[] { const funs: string[] = [] const callback = ffi.Callback(ref.types.void, [PgfItorPtr, PgfTextPtr, voidPtr, PgfExnPtr], function (self: Pointer, key: Pointer, value: Pointer, err: Pointer) { const k = PgfText_AsString(key) funs.push(k) }) const err = new PgfExn() runtime.pgf_iter_functions(this.db, this.revision.deref(), callback.ref() as Pointer, err.ref()) handleError(err) return funs } categoryProbability (cat: string): number | undefined { const catname = PgfText_FromString(cat) const err = new PgfExn() const prob = runtime.pgf_category_prob(this.db, this.revision.deref(), catname, err.ref()) handleError(err) if (prob === Infinity) { return undefined } else { return prob } } functionProbability (fun: string): number | undefined { const funname = PgfText_FromString(fun) const err = new PgfExn() const prob = runtime.pgf_function_prob(this.db, this.revision.deref(), funname, err.ref()) handleError(err) if (prob === Infinity) { return undefined } else { return prob } } functionIsConstructor (fun: string): boolean { const funname = PgfText_FromString(fun) const err = new PgfExn() const isCon = runtime.pgf_function_is_constructor(this.db, this.revision.deref(), funname, err.ref()) handleError(err) return Boolean(isCon) } functionsByCategory (cat: string): string[] { const catname = PgfText_FromString(cat) const funs: string[] = [] const callback = ffi.Callback(ref.types.void, [PgfItorPtr, PgfTextPtr, voidPtr, PgfExnPtr], function (self: Pointer, key: Pointer, value: Pointer, err: Pointer) { const k = PgfText_AsString(key) funs.push(k) }) const err = new PgfExn() runtime.pgf_iter_functions_by_cat(this.db, this.revision.deref(), catname, callback.ref() as Pointer, err.ref()) handleError(err) return funs } } // ---------------------------------------------------------------------------- // PGF module functions function readPGF (path: string): PGFGrammar { const rev = ref.alloc(PgfRevisionPtr) const err = new PgfExn() const db = runtime.pgf_read_pgf(path, rev, err.ref()) handleError(err) return new PGFGrammar(db, rev) } function bootNGF (pgf_path: string, ngf_path: string): PGFGrammar { const rev = ref.alloc(PgfRevisionPtr) const err = new PgfExn() const db = runtime.pgf_boot_ngf(pgf_path, ngf_path, rev, err.ref()) handleError(err) 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) } function readType (str: string): Type { const txt = PgfText_FromString(str) const type = runtime.pgf_read_type(txt, unmarshaller.ref()) if (ref.isNull(type)) { throw new PGFError('unable to parse type') } return ref.readObject(type) as Type } function readExpr (str: string): Expr { const txt = PgfText_FromString(str) const expr = runtime.pgf_read_expr(txt, unmarshaller.ref()) if (ref.isNull(expr)) { throw new PGFError('unable to parse expression') } return ref.readObject(expr) as Expr } function showType (context: string[], type: Type): string { return 'TODO' } // ---------------------------------------------------------------------------- // Exposed library API export { PGFGrammar, PGFError, readPGF, bootNGF, readNGF, newNGF, readType, readExpr, showType, Type, mkType, Hypo, mkHypo, mkDepHypo, mkImplHypo, Expr, ExprAbs, ExprApp, ExprLit, ExprMeta, ExprFun, ExprVar, ExprTyped, ExprImplArg, Literal } export default { PGFGrammar, PGFError, readPGF, bootNGF, readNGF, newNGF, readType, readExpr, showType, Type, mkType, Hypo, mkHypo, mkDepHypo, mkImplHypo, Expr, ExprAbs, ExprApp, ExprLit, ExprMeta, ExprFun, ExprVar, ExprTyped, ExprImplArg, Literal }