From db0cbf60cb23d336439793baf600094f77c0f41d Mon Sep 17 00:00:00 2001 From: "John J. Camilleri" Date: Thu, 7 Oct 2021 15:07:14 +0200 Subject: [PATCH] Support big and negative integers --- src/runtime/javascript/expr.ts | 6 ++-- src/runtime/javascript/ffi.ts | 31 ++++++++++++++++++-- src/runtime/javascript/tests/basic.test.ts | 34 ++++++++++++++++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/runtime/javascript/expr.ts b/src/runtime/javascript/expr.ts index 45d10effc..5b6d7b90b 100644 --- a/src/runtime/javascript/expr.ts +++ b/src/runtime/javascript/expr.ts @@ -31,7 +31,7 @@ export class ExprApp extends Expr { } export class ExprLit extends Expr { lit: Literal - constructor (l: Literal | number | string) { + constructor (l: Literal | number | bigint | string) { super() if (l instanceof Literal) this.lit = l else this.lit = new Literal(l) @@ -58,8 +58,8 @@ export class ExprImplArg extends Expr { } export class Literal { - val: number | string - constructor (v: number | string) { + val: number | bigint | string + constructor (v: number | bigint | string) { this.val = v } diff --git a/src/runtime/javascript/ffi.ts b/src/runtime/javascript/ffi.ts index be9cdcfec..5e9a41953 100644 --- a/src/runtime/javascript/ffi.ts +++ b/src/runtime/javascript/ffi.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { ExprLit, Literal } from './expr' +import os from 'os' import ffi from 'ffi-napi' import ref, { Pointer } from 'ref-napi' import ref_struct from 'ref-struct-di' @@ -37,9 +38,34 @@ const elit = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfLiteral], 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): Pointer { - 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 ref.writeObject(buf, 0, obj) 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)], function (self, x: any): void { - // console.log('free_ref') }) const vtbl = new PgfUnmarshallerVtbl({ diff --git a/src/runtime/javascript/tests/basic.test.ts b/src/runtime/javascript/tests/basic.test.ts index 9a40e70ed..51c6433ba 100644 --- a/src/runtime/javascript/tests/basic.test.ts +++ b/src/runtime/javascript/tests/basic.test.ts @@ -218,7 +218,7 @@ describe('expressions', () => { expect(e1).not.toEqual(e3) }) - test.skip('negative integer', () => { + test('negative integer', () => { const e1 = PGF.readExpr('-123') const e2 = new PGF.ExprLit(-123) const e3 = new PGF.ExprLit(-456) @@ -226,9 +226,31 @@ describe('expressions', () => { expect(e1).not.toEqual(e3) }) - // test.only('big integer', () => { - // const e1 = PGF.readExpr('774763251095801167872') - // const e2 = new PGF.ExprLit(BigInt(774763251095801167872)) - // expect(e1).toEqual(e2) - // }) + test('big integer', () => { + const e1 = PGF.readExpr('774763251095801167872') + const e2 = new PGF.ExprLit(BigInt('774763251095801167872')) + 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) + }) })