mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-17 08:49:31 -06:00
Add proper tests, exception handling, implement getAbstractName
This commit is contained in:
@@ -1,44 +1,122 @@
|
||||
import errno from './errno'
|
||||
import ffi from 'ffi'
|
||||
import { deref } from 'ref'
|
||||
import * as ref from 'ref'
|
||||
import * as ffi from 'ffi'
|
||||
import ref from 'ref'
|
||||
import Struct from 'ref-struct'
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// FFI "Types"
|
||||
|
||||
const PgfDB = ref.types.int
|
||||
const PgfDBPtr = ref.refType(PgfDB)
|
||||
const PgfRevision = ref.types.int
|
||||
const PgfRevisionPtr = ref.refType(PgfRevision)
|
||||
const PgfExn = ref.types.int
|
||||
const PgfExnPtr = ref.refType(PgfExn)
|
||||
// const stringPtr = ref.refType(ref.types.CString)
|
||||
|
||||
const PGF = ffi.Library('libpgf', {
|
||||
'pgf_read_pgf': [ PgfDBPtr, [ 'string', PgfRevisionPtr, PgfExnPtr ] ],
|
||||
'pgf_write_pgf': [ 'void', [ 'string', PgfDBPtr, PgfRevisionPtr, PgfExnPtr ] ],
|
||||
const PgfExn = Struct({
|
||||
type: ref.types.int,
|
||||
code: ref.types.int,
|
||||
msg: ref.types.CString
|
||||
})
|
||||
const PgfExnPtr = ref.refType(PgfExn)
|
||||
const PgfText = Struct({
|
||||
size: ref.types.size_t,
|
||||
text: ref.types.char // char[]
|
||||
})
|
||||
const PgfTextPtr = ref.refType(PgfText)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TypeScript Types
|
||||
|
||||
interface Pointer extends Buffer {
|
||||
deref(): any
|
||||
}
|
||||
|
||||
interface State {
|
||||
db: Pointer,
|
||||
revision: number
|
||||
}
|
||||
const state: State = {
|
||||
db: ref.NULL_POINTER as Pointer,
|
||||
revision: 0
|
||||
}
|
||||
|
||||
export default {
|
||||
readPGF: function (path: string) {
|
||||
const rev = ref.alloc(PgfRevision) as Pointer
|
||||
const err = ref.alloc(PgfExn) as Pointer
|
||||
const db = PGF.pgf_read_pgf(path, rev, err)
|
||||
if (err.deref() === 0) {
|
||||
state.db = db
|
||||
state.revision = rev.deref()
|
||||
console.log(`ok`)
|
||||
} else {
|
||||
console.error(`error ${err.deref()}`)
|
||||
}
|
||||
class PGFError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// FFI
|
||||
|
||||
const runtime = ffi.Library('libpgf', {
|
||||
'pgf_read_pgf': [ PgfDBPtr, [ ref.types.CString, PgfRevisionPtr, PgfExnPtr ] ],
|
||||
'pgf_write_pgf': [ ref.types.void, [ ref.types.CString, PgfDBPtr, PgfRevisionPtr, PgfExnPtr ] ],
|
||||
'pgf_abstract_name': [ PgfTextPtr, [ PgfDBPtr, PgfRevision, PgfExnPtr ] ],
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
|
||||
function handleError (errPtr: Pointer): void {
|
||||
const err = errPtr.deref()
|
||||
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}: ${err.msg}`)
|
||||
|
||||
// PGF_EXN_PGF_ERROR
|
||||
case 2:
|
||||
throw new PGFError(err.msg)
|
||||
|
||||
// PGF_EXN_OTHER_ERROR
|
||||
case 3:
|
||||
throw new Error(err.msg)
|
||||
|
||||
default:
|
||||
throw new Error(`unknown error type: ${err.type}`)
|
||||
}
|
||||
}
|
||||
|
||||
function PgfText_AsString (txtPtr: Pointer) {
|
||||
const txtSize = txtPtr.deref().size
|
||||
const charPtr = ref.reinterpret(txtPtr, txtSize, ref.types.size_t.size)
|
||||
return charPtr.toString('utf8')
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PGF grammar object
|
||||
|
||||
class PGF {
|
||||
db: Pointer
|
||||
revision: number
|
||||
|
||||
constructor () {
|
||||
this.db = ref.NULL_POINTER as Pointer
|
||||
this.revision = 0
|
||||
}
|
||||
|
||||
getAbstractName () {
|
||||
const err = ref.alloc(PgfExn) as Pointer
|
||||
const txt = runtime.pgf_abstract_name(this.db, this.revision, err)
|
||||
handleError(err)
|
||||
return PgfText_AsString(txt)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PGF module functions
|
||||
|
||||
function readPGF (path: string): PGF {
|
||||
const rev = ref.alloc(PgfRevision) as Pointer
|
||||
const err = ref.alloc(PgfExn) as Pointer
|
||||
const db = runtime.pgf_read_pgf(path, rev, err)
|
||||
handleError(err)
|
||||
|
||||
const state = new PGF()
|
||||
state.db = db
|
||||
state.revision = rev.deref()
|
||||
return state
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Exposed library API
|
||||
|
||||
export default {
|
||||
readPGF
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user