mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-23 11:42:49 -06:00
Support big and negative integers
This commit is contained in:
@@ -31,7 +31,7 @@ export class ExprApp extends Expr {
|
|||||||
}
|
}
|
||||||
export class ExprLit extends Expr {
|
export class ExprLit extends Expr {
|
||||||
lit: Literal
|
lit: Literal
|
||||||
constructor (l: Literal | number | string) {
|
constructor (l: Literal | number | bigint | string) {
|
||||||
super()
|
super()
|
||||||
if (l instanceof Literal) this.lit = l
|
if (l instanceof Literal) this.lit = l
|
||||||
else this.lit = new Literal(l)
|
else this.lit = new Literal(l)
|
||||||
@@ -58,8 +58,8 @@ export class ExprImplArg extends Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Literal {
|
export class Literal {
|
||||||
val: number | string
|
val: number | bigint | string
|
||||||
constructor (v: number | string) {
|
constructor (v: number | bigint | string) {
|
||||||
this.val = v
|
this.val = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { ExprLit, Literal } from './expr'
|
import { ExprLit, Literal } from './expr'
|
||||||
|
|
||||||
|
import os from 'os'
|
||||||
import ffi from 'ffi-napi'
|
import ffi from 'ffi-napi'
|
||||||
import ref, { Pointer } from 'ref-napi'
|
import ref, { Pointer } from 'ref-napi'
|
||||||
import ref_struct from 'ref-struct-di'
|
import ref_struct from 'ref-struct-di'
|
||||||
@@ -37,9 +38,34 @@ const elit = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfLiteral],
|
|||||||
return buf
|
return buf
|
||||||
})
|
})
|
||||||
|
|
||||||
const lint = ffi.Callback(PgfLiteral, [PgfUnmarshaller, ref.types.size_t, ref.refType(ref.types.uint)],
|
// TODO get from platform/runtime
|
||||||
|
const WORDSIZE_BITS = 64
|
||||||
|
const WORDSIZE_BYTES = WORDSIZE_BITS / 8
|
||||||
|
const LINT_BASE = BigInt('10000000000000000000')
|
||||||
|
|
||||||
|
const lint = ffi.Callback(PgfLiteral, [PgfUnmarshaller, ref.types.size_t, ref.refType(ref.types.int)],
|
||||||
function (self, size: number, val: Pointer<number>): Pointer<Literal> {
|
function (self, size: number, val: Pointer<number>): Pointer<Literal> {
|
||||||
const obj = new Literal(val.deref())
|
let jsval: number | bigint = 0
|
||||||
|
if (size === 1) {
|
||||||
|
jsval = val.deref()
|
||||||
|
} else if (size > 1) {
|
||||||
|
jsval = BigInt(val.deref())
|
||||||
|
const pos = jsval >= 0
|
||||||
|
const vals = ref.reinterpret(val, size * WORDSIZE_BYTES)
|
||||||
|
for (let n = 1; n < size; n++) {
|
||||||
|
let thisval
|
||||||
|
switch (WORDSIZE_BITS) {
|
||||||
|
case 64:
|
||||||
|
thisval = BigInt((os.endianness() === 'LE') ? vals.readUInt64LE(n * WORDSIZE_BYTES) : vals.readUInt64BE(n * WORDSIZE_BYTES))
|
||||||
|
}
|
||||||
|
if (thisval == null) {
|
||||||
|
throw Error(`Unsupported word size: ${WORDSIZE_BITS}`)
|
||||||
|
}
|
||||||
|
jsval = (jsval * LINT_BASE) + (pos ? thisval : -thisval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj = new Literal(jsval)
|
||||||
const buf = ref.alloc(ref.types.Object) as Pointer<Literal>
|
const buf = ref.alloc(ref.types.Object) as Pointer<Literal>
|
||||||
ref.writeObject(buf, 0, obj)
|
ref.writeObject(buf, 0, obj)
|
||||||
return buf
|
return buf
|
||||||
@@ -47,7 +73,6 @@ const lint = ffi.Callback(PgfLiteral, [PgfUnmarshaller, ref.types.size_t, ref.re
|
|||||||
|
|
||||||
const free_ref = ffi.Callback(ref.types.void, [PgfUnmarshaller, ref.refType(ref.types.void)],
|
const free_ref = ffi.Callback(ref.types.void, [PgfUnmarshaller, ref.refType(ref.types.void)],
|
||||||
function (self, x: any): void {
|
function (self, x: any): void {
|
||||||
// console.log('free_ref')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const vtbl = new PgfUnmarshallerVtbl({
|
const vtbl = new PgfUnmarshallerVtbl({
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ describe('expressions', () => {
|
|||||||
expect(e1).not.toEqual(e3)
|
expect(e1).not.toEqual(e3)
|
||||||
})
|
})
|
||||||
|
|
||||||
test.skip('negative integer', () => {
|
test('negative integer', () => {
|
||||||
const e1 = PGF.readExpr('-123')
|
const e1 = PGF.readExpr('-123')
|
||||||
const e2 = new PGF.ExprLit(-123)
|
const e2 = new PGF.ExprLit(-123)
|
||||||
const e3 = new PGF.ExprLit(-456)
|
const e3 = new PGF.ExprLit(-456)
|
||||||
@@ -226,9 +226,31 @@ describe('expressions', () => {
|
|||||||
expect(e1).not.toEqual(e3)
|
expect(e1).not.toEqual(e3)
|
||||||
})
|
})
|
||||||
|
|
||||||
// test.only('big integer', () => {
|
test('big integer', () => {
|
||||||
// const e1 = PGF.readExpr('774763251095801167872')
|
const e1 = PGF.readExpr('774763251095801167872')
|
||||||
// const e2 = new PGF.ExprLit(BigInt(774763251095801167872))
|
const e2 = new PGF.ExprLit(BigInt('774763251095801167872'))
|
||||||
// expect(e1).toEqual(e2)
|
expect(e1).toEqual(e2)
|
||||||
// })
|
})
|
||||||
|
|
||||||
|
test('negative big integer', () => {
|
||||||
|
const e1 = PGF.readExpr('-774763251095801167872')
|
||||||
|
const e2 = new PGF.ExprLit(BigInt('-774763251095801167872'))
|
||||||
|
expect(e1).toEqual(e2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('really big integer', () => {
|
||||||
|
const e1 = PGF.readExpr('7747632510958011678729003251095801167999')
|
||||||
|
const e2 = new PGF.ExprLit(BigInt('7747632510958011678729003251095801167999'))
|
||||||
|
const e3 = new PGF.ExprLit(BigInt('7747632510958011678729003251095801167990'))
|
||||||
|
expect(e1).toEqual(e2)
|
||||||
|
expect(e1).not.toEqual(e3)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('negative really big integer', () => {
|
||||||
|
const e1 = PGF.readExpr('-7747632510958011678729003251095801167999')
|
||||||
|
const e2 = new PGF.ExprLit(BigInt('-7747632510958011678729003251095801167999'))
|
||||||
|
const e3 = new PGF.ExprLit(BigInt('-7747632510958011678729003251095801167990'))
|
||||||
|
expect(e1).toEqual(e2)
|
||||||
|
expect(e1).not.toEqual(e3)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user