forked from GitHub/gf-core
Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
## Requirements
|
||||
|
||||
Required system packages (Debian/Ubuntu):
|
||||
### Debian/Ubuntu
|
||||
|
||||
Required system packages (`apt install ...`):
|
||||
```
|
||||
autoconf
|
||||
automake
|
||||
@@ -11,6 +13,11 @@ make
|
||||
g++
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
- Install XCode from App Store
|
||||
- Install XCode command line tools: `xcode-select --install`
|
||||
|
||||
## Installation
|
||||
|
||||
Installing the runtime (puts libraries in `/usr/local/lib`):
|
||||
|
||||
@@ -30,3 +30,12 @@ npm run build
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
## Known issues
|
||||
|
||||
There is a known issue with random crashes with Node 14 and 16 on macOS. See here:
|
||||
- https://github.com/nodejs/node/issues/32463
|
||||
- https://github.com/node-ffi-napi/node-ffi-napi/issues/97
|
||||
- https://github.com/node-ffi-napi/ref-napi/issues/47
|
||||
|
||||
It seems to work with Node 12 on macOS, as well as on other platforms.
|
||||
|
||||
39
src/runtime/javascript/constants.ts
Normal file
39
src/runtime/javascript/constants.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// Untested!
|
||||
import os from 'os'
|
||||
|
||||
export const BE: boolean = os.endianness() === 'BE'
|
||||
|
||||
export let WORDSIZE_BITS: number
|
||||
switch (process.arch) {
|
||||
case 'arm':
|
||||
case 'ia32':
|
||||
case 'ppc':
|
||||
case 's390':
|
||||
case 'x32':
|
||||
WORDSIZE_BITS = 32
|
||||
break
|
||||
|
||||
case 'arm64':
|
||||
case 'mips':
|
||||
case 'mipsel':
|
||||
case 'ppc64':
|
||||
case 's390x':
|
||||
case 'x64':
|
||||
WORDSIZE_BITS = 64
|
||||
break
|
||||
|
||||
default:
|
||||
throw Error(`Unknown architecture: ${process.arch}`)
|
||||
}
|
||||
|
||||
export const WORDSIZE_BYTES = WORDSIZE_BITS / 8
|
||||
|
||||
export let LINT_BASE: bigint
|
||||
|
||||
switch (WORDSIZE_BITS) {
|
||||
case 64: LINT_BASE = BigInt('10000000000000000000'); break
|
||||
case 32: LINT_BASE = BigInt('1000000000'); break
|
||||
case 16: LINT_BASE = BigInt('10000'); break
|
||||
case 8: LINT_BASE = BigInt('100'); break
|
||||
default: throw Error(`Unsupported word size: ${WORDSIZE_BITS}`)
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
export class Type {
|
||||
hypos!: Hypo[]
|
||||
name!: string
|
||||
exprs!: Expr[]
|
||||
hypos: Hypo[]
|
||||
name: string
|
||||
exprs: Expr[]
|
||||
|
||||
constructor (hs: Hypo[], n: string, es: Expr[]) {
|
||||
this.hypos = hs
|
||||
this.name = n
|
||||
this.exprs = es
|
||||
}
|
||||
}
|
||||
|
||||
export class Hypo {
|
||||
@@ -11,6 +17,7 @@ export class Hypo {
|
||||
}
|
||||
|
||||
export class Expr {
|
||||
// TODO overload
|
||||
constructor (n?: number) {
|
||||
if (n != null) {
|
||||
return new ExprLit(n)
|
||||
@@ -24,13 +31,32 @@ export class Expr {
|
||||
}
|
||||
|
||||
export class ExprAbs extends Expr {
|
||||
bind_type: boolean
|
||||
name: string
|
||||
body: Expr
|
||||
|
||||
constructor (bt: boolean, n: string, b: Expr) {
|
||||
super()
|
||||
this.bind_type = bt
|
||||
this.name = n
|
||||
this.body = b
|
||||
}
|
||||
}
|
||||
|
||||
export class ExprApp extends Expr {
|
||||
fun: Expr
|
||||
arg: Expr
|
||||
|
||||
constructor (f: Expr, a: Expr) {
|
||||
super()
|
||||
this.fun = f
|
||||
this.arg = a
|
||||
}
|
||||
}
|
||||
|
||||
export class ExprLit extends Expr {
|
||||
lit: Literal
|
||||
|
||||
constructor (l: Literal | number | bigint | string) {
|
||||
super()
|
||||
if (l instanceof Literal) this.lit = l
|
||||
@@ -41,24 +67,58 @@ export class ExprLit extends Expr {
|
||||
return this.lit.toString()
|
||||
}
|
||||
}
|
||||
|
||||
export class ExprMeta extends Expr {
|
||||
id: number
|
||||
|
||||
constructor (i?: number) {
|
||||
super()
|
||||
if (i != null) this.id = i
|
||||
else this.id = 0
|
||||
}
|
||||
}
|
||||
|
||||
export class ExprFun extends Expr {
|
||||
name: string
|
||||
|
||||
constructor (n: string) {
|
||||
super()
|
||||
this.name = n
|
||||
}
|
||||
}
|
||||
|
||||
export class ExprVar extends Expr {
|
||||
var: number
|
||||
|
||||
constructor (v: number) {
|
||||
super()
|
||||
this.var = v
|
||||
}
|
||||
}
|
||||
|
||||
export class ExprTyped extends Expr {
|
||||
expr: Expr
|
||||
type: Type
|
||||
|
||||
constructor (e: Expr, t: Type) {
|
||||
super()
|
||||
this.expr = e
|
||||
this.type = t
|
||||
}
|
||||
}
|
||||
export class ExprImplArg extends Expr {
|
||||
|
||||
export class ExprImplArg extends Expr {
|
||||
expr: Expr
|
||||
|
||||
constructor (e: Expr) {
|
||||
super()
|
||||
this.expr = e
|
||||
}
|
||||
}
|
||||
|
||||
export class Literal {
|
||||
val: number | bigint | string
|
||||
|
||||
constructor (v: number | bigint | string) {
|
||||
this.val = v
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import {
|
||||
Type,
|
||||
// Hypo,
|
||||
Hypo,
|
||||
Expr,
|
||||
ExprAbs,
|
||||
ExprApp,
|
||||
ExprLit,
|
||||
@@ -12,8 +13,8 @@ import {
|
||||
ExprImplArg,
|
||||
Literal
|
||||
} from './expr'
|
||||
import { BE, WORDSIZE_BITS, WORDSIZE_BYTES, LINT_BASE } from './constants'
|
||||
|
||||
import os from 'os'
|
||||
import ffi from 'ffi-napi'
|
||||
import ref, { Pointer } from 'ref-napi'
|
||||
import ref_struct from 'ref-struct-di'
|
||||
@@ -47,7 +48,7 @@ export const PgfTextPtr = ref.refType(PgfText)
|
||||
|
||||
export const PgfItorPtr = ref.refType(ref.types.void)
|
||||
|
||||
const PgfType = ref.types.void // TODO
|
||||
const PgfType = ref.refType(ref.types.Object) // TODO
|
||||
// const PgfTypePtr = ref.refType(PgfType)
|
||||
|
||||
const PgfTypeHypo = ref.types.void // TODO
|
||||
@@ -158,18 +159,25 @@ export function PgfText_FromString (str: string): Pointer<any> {
|
||||
// Un/marshalling
|
||||
|
||||
const eabs = ffi.Callback(PgfExpr, [PgfUnmarshaller, ref.types.bool, PgfTextPtr, PgfExpr],
|
||||
function (self, btype: boolean, name: Pointer<any>, body: Pointer<any>): Pointer<ExprAbs> {
|
||||
return 0 as any
|
||||
function (self, btype: boolean, name: Pointer<any>, body: Pointer<Expr>): Pointer<ExprAbs> {
|
||||
const jsname = PgfText_AsString(name)
|
||||
const obj = new ExprAbs(btype, jsname, body.deref())
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprAbs>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const eapp = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfExpr, PgfExpr],
|
||||
function (self, fun: Pointer<any>, arg: Pointer<any>): Pointer<ExprApp> {
|
||||
return 0 as any
|
||||
function (self, fun: Pointer<Expr>, arg: Pointer<Type>): Pointer<ExprApp> {
|
||||
const obj = new ExprApp(fun.deref(), arg.deref())
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprApp>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const elit = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfLiteral],
|
||||
function (self, lit: Pointer<any>): Pointer<ExprLit> {
|
||||
const litObj = lit.deref() as Literal
|
||||
function (self, lit: Pointer<Literal>): Pointer<ExprLit> {
|
||||
const litObj = lit.deref()
|
||||
const obj = new ExprLit(litObj)
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprLit>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
@@ -177,35 +185,46 @@ const elit = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfLiteral],
|
||||
})
|
||||
|
||||
const emeta = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfMetaId],
|
||||
function (self, meta: Pointer<any>): Pointer<ExprMeta> {
|
||||
return 0 as any
|
||||
function (self, meta: number): Pointer<ExprMeta> {
|
||||
const obj = new ExprMeta(meta)
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprMeta>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const efun = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfTextPtr],
|
||||
function (self, name: Pointer<any>): Pointer<ExprFun> {
|
||||
return 0 as any
|
||||
const jsname = PgfText_AsString(name)
|
||||
const obj = new ExprFun(jsname)
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprFun>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const evar = ffi.Callback(PgfExpr, [PgfUnmarshaller, ref.types.int],
|
||||
function (self, index: number): Pointer<ExprVar> {
|
||||
return 0 as any
|
||||
const obj = new ExprVar(index)
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprVar>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const etyped = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfExpr, PgfType],
|
||||
function (self, expr: Pointer<any>, type: Pointer<any>): Pointer<ExprTyped> {
|
||||
return 0 as any
|
||||
function (self, expr: Pointer<Expr>, type: Pointer<Type>): Pointer<ExprTyped> {
|
||||
const obj = new ExprTyped(expr.deref(), type.deref())
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprTyped>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const eimplarg = ffi.Callback(PgfExpr, [PgfUnmarshaller, PgfExpr],
|
||||
function (self, expr: Pointer<any>): Pointer<ExprImplArg> {
|
||||
return 0 as any
|
||||
function (self, expr: Pointer<Expr>): Pointer<ExprImplArg> {
|
||||
const obj = new ExprImplArg(expr.deref())
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<ExprImplArg>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
// 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> {
|
||||
let jsval: number | bigint = 0
|
||||
@@ -219,7 +238,17 @@ const lint = ffi.Callback(PgfLiteral, [PgfUnmarshaller, ref.types.size_t, ref.re
|
||||
let thisval
|
||||
switch (WORDSIZE_BITS) {
|
||||
case 64:
|
||||
thisval = BigInt((os.endianness() === 'LE') ? vals.readUInt64LE(n * WORDSIZE_BYTES) : vals.readUInt64BE(n * WORDSIZE_BYTES))
|
||||
thisval = BigInt(BE ? vals.readUInt64BE(n * WORDSIZE_BYTES) : vals.readUInt64LE(n * WORDSIZE_BYTES))
|
||||
break
|
||||
case 32:
|
||||
thisval = BigInt(BE ? vals.readUInt32BE(n * WORDSIZE_BYTES) : vals.readUInt32LE(n * WORDSIZE_BYTES))
|
||||
break
|
||||
case 16:
|
||||
thisval = BigInt(BE ? vals.readUInt16BE(n * WORDSIZE_BYTES) : vals.readUInt16LE(n * WORDSIZE_BYTES))
|
||||
break
|
||||
case 8:
|
||||
thisval = BigInt(vals.readUInt8(n * WORDSIZE_BYTES))
|
||||
break
|
||||
}
|
||||
if (thisval == null) {
|
||||
throw Error(`Unsupported word size: ${WORDSIZE_BITS}`)
|
||||
@@ -253,7 +282,14 @@ const lstr = ffi.Callback(PgfLiteral, [PgfUnmarshaller, PgfTextPtr],
|
||||
|
||||
const dtyp = ffi.Callback(PgfType, [PgfUnmarshaller, ref.types.int, PgfTypeHypoPtr, PgfTextPtr, ref.types.int, ref.refType(PgfExpr)],
|
||||
function (self, n_hypos: number, hypos: Pointer<any>, cat: Pointer<any>, n_exprs: number, exprs: Pointer<any>): Pointer<Type> {
|
||||
return 0 as any
|
||||
// TODO
|
||||
const jshypos: Hypo[] = []
|
||||
const jsname = PgfText_AsString(cat)
|
||||
const jsexprs: Expr[] = []
|
||||
const obj = new Type(jshypos, jsname, jsexprs)
|
||||
const buf = ref.alloc(ref.types.Object) as Pointer<Type>
|
||||
ref.writeObject(buf, 0, obj)
|
||||
return buf
|
||||
})
|
||||
|
||||
const free_ref = ffi.Callback(ref.types.void, [PgfUnmarshaller, ref.refType(ref.types.Object)],
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import errno from './errno'
|
||||
import { Expr, ExprLit } from './expr'
|
||||
import {
|
||||
Type,
|
||||
Hypo,
|
||||
Expr,
|
||||
ExprAbs,
|
||||
ExprApp,
|
||||
ExprLit,
|
||||
ExprMeta,
|
||||
ExprFun,
|
||||
ExprVar,
|
||||
ExprTyped,
|
||||
ExprImplArg,
|
||||
Literal
|
||||
} from './expr'
|
||||
import {
|
||||
voidPtr,
|
||||
PgfRevisionPtr,
|
||||
@@ -67,7 +80,7 @@ function handleError (err: StructObject<PgfExnType>): void {
|
||||
// ----------------------------------------------------------------------------
|
||||
// PGF grammar object
|
||||
|
||||
export class PGFGrammar {
|
||||
class PGFGrammar {
|
||||
readonly db: Pointer<any>
|
||||
readonly revision: Pointer<any>
|
||||
|
||||
@@ -198,24 +211,72 @@ function newNGF (abstract_name: string, path?: string): PGFGrammar {
|
||||
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
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Exposed library API
|
||||
|
||||
export default {
|
||||
export {
|
||||
PGFGrammar,
|
||||
PGFError,
|
||||
readPGF,
|
||||
bootNGF,
|
||||
readNGF,
|
||||
newNGF,
|
||||
|
||||
readType,
|
||||
readExpr,
|
||||
|
||||
Type,
|
||||
Hypo,
|
||||
Expr,
|
||||
ExprLit
|
||||
ExprAbs,
|
||||
ExprApp,
|
||||
ExprLit,
|
||||
ExprMeta,
|
||||
ExprFun,
|
||||
ExprVar,
|
||||
ExprTyped,
|
||||
ExprImplArg,
|
||||
Literal
|
||||
}
|
||||
export default {
|
||||
PGFGrammar,
|
||||
PGFError,
|
||||
readPGF,
|
||||
bootNGF,
|
||||
readNGF,
|
||||
newNGF,
|
||||
|
||||
readType,
|
||||
readExpr,
|
||||
|
||||
Type,
|
||||
Hypo,
|
||||
Expr,
|
||||
ExprAbs,
|
||||
ExprApp,
|
||||
ExprLit,
|
||||
ExprMeta,
|
||||
ExprFun,
|
||||
ExprVar,
|
||||
ExprTyped,
|
||||
ExprImplArg,
|
||||
Literal
|
||||
}
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
import PGF, { PGFGrammar } from '../index'
|
||||
import PGF, {
|
||||
PGFError,
|
||||
PGFGrammar,
|
||||
// Type,
|
||||
// Hypo,
|
||||
// Expr,
|
||||
// ExprAbs,
|
||||
ExprApp,
|
||||
ExprLit,
|
||||
ExprMeta,
|
||||
ExprFun,
|
||||
// ExprVar,
|
||||
// ExprTyped,
|
||||
ExprImplArg
|
||||
// Literal
|
||||
} from '../index'
|
||||
import fs from 'fs'
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -17,7 +32,7 @@ describe('readPGF', () => {
|
||||
test('GF', () => {
|
||||
expect(() => {
|
||||
PGF.readPGF('../haskell/tests/basic.gf')
|
||||
}).toThrow(PGF.PGFError)
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
|
||||
test('NGF', () => {
|
||||
@@ -29,7 +44,7 @@ describe('readPGF', () => {
|
||||
PGF.bootNGF('../haskell/tests/basic.pgf', './basic.ngf')
|
||||
expect(() => {
|
||||
PGF.readPGF('./basic.ngf')
|
||||
}).toThrow(PGF.PGFError)
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -57,13 +72,13 @@ describe('bootNGF', () => {
|
||||
test('GF', () => {
|
||||
expect(() => {
|
||||
PGF.bootNGF('../haskell/tests/basic.gf', './abc.ngf')
|
||||
}).toThrow(PGF.PGFError)
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
|
||||
test('NGF', () => {
|
||||
expect(() => {
|
||||
PGF.bootNGF('./basic.ngf', './abc.ngf')
|
||||
}).toThrow(PGF.PGFError)
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
|
||||
test('existing', () => {
|
||||
@@ -98,13 +113,13 @@ describe('readNGF', () => {
|
||||
test('GF', () => {
|
||||
expect(() => {
|
||||
PGF.readNGF('../haskell/tests/basic.gf')
|
||||
}).toThrow(PGF.PGFError)
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
|
||||
test('PGF', () => {
|
||||
expect(() => {
|
||||
PGF.readNGF('../haskell/tests/basic.pgf')
|
||||
}).toThrow(PGF.PGFError)
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -209,80 +224,170 @@ describe('abstract syntax', () => {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
describe('expressions', () => {
|
||||
test('small integer', () => {
|
||||
const e1 = PGF.readExpr('123')
|
||||
const e2 = new PGF.ExprLit(123)
|
||||
const e3 = new PGF.ExprLit(456)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('negative integer', () => {
|
||||
const e1 = PGF.readExpr('-123')
|
||||
const e2 = new PGF.ExprLit(-123)
|
||||
const e3 = new PGF.ExprLit(-456)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
test('float', () => {
|
||||
const e1 = PGF.readExpr('3.142')
|
||||
const e2 = new PGF.ExprLit(3.142)
|
||||
const e3 = new PGF.ExprLit(2.014)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('negative float', () => {
|
||||
const e1 = PGF.readExpr('-3.142')
|
||||
const e2 = new PGF.ExprLit(-3.142)
|
||||
const e3 = new PGF.ExprLit(-2.014)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('string', () => {
|
||||
const e1 = PGF.readExpr('"abc"')
|
||||
const e2 = new PGF.ExprLit('abc')
|
||||
const e3 = new PGF.ExprLit('def')
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('string unicode', () => {
|
||||
const e1 = PGF.readExpr('"açġħ"')
|
||||
const e2 = new PGF.ExprLit('açġħ')
|
||||
const e3 = new PGF.ExprLit('acgh')
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
describe('types', () => {
|
||||
test('invalid', () => {
|
||||
expect(() => {
|
||||
PGF.readType('->')
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
describe('expressions', () => {
|
||||
test('invalid', () => {
|
||||
expect(() => {
|
||||
PGF.readExpr('->')
|
||||
}).toThrow(PGFError)
|
||||
})
|
||||
|
||||
describe('literals', () => {
|
||||
test('small integer', () => {
|
||||
const e1 = PGF.readExpr('123')
|
||||
const e2 = new ExprLit(123)
|
||||
const e3 = new ExprLit(456)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('negative integer', () => {
|
||||
const e1 = PGF.readExpr('-123')
|
||||
const e2 = new ExprLit(-123)
|
||||
const e3 = new ExprLit(-456)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('big integer', () => {
|
||||
const e1 = PGF.readExpr('774763251095801167872')
|
||||
const e2 = new ExprLit(BigInt('774763251095801167872'))
|
||||
expect(e1).toEqual(e2)
|
||||
})
|
||||
|
||||
test('negative big integer', () => {
|
||||
const e1 = PGF.readExpr('-774763251095801167872')
|
||||
const e2 = new ExprLit(BigInt('-774763251095801167872'))
|
||||
expect(e1).toEqual(e2)
|
||||
})
|
||||
|
||||
test('really big integer', () => {
|
||||
const e1 = PGF.readExpr('7747632510958011678729003251095801167999')
|
||||
const e2 = new ExprLit(BigInt('7747632510958011678729003251095801167999'))
|
||||
const e3 = new 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 ExprLit(BigInt('-7747632510958011678729003251095801167999'))
|
||||
const e3 = new ExprLit(BigInt('-7747632510958011678729003251095801167990'))
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('float', () => {
|
||||
const e1 = PGF.readExpr('3.142')
|
||||
const e2 = new ExprLit(3.142)
|
||||
const e3 = new ExprLit(2.014)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('negative float', () => {
|
||||
const e1 = PGF.readExpr('-3.142')
|
||||
const e2 = new ExprLit(-3.142)
|
||||
const e3 = new ExprLit(-2.014)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('string', () => {
|
||||
const e1 = PGF.readExpr('"abc"')
|
||||
const e2 = new ExprLit('abc')
|
||||
const e3 = new ExprLit('def')
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('string unicode', () => {
|
||||
const e1 = PGF.readExpr('"açġħ"')
|
||||
const e2 = new ExprLit('açġħ')
|
||||
const e3 = new ExprLit('acgh')
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
})
|
||||
|
||||
describe('functions', () => {
|
||||
test('simple', () => {
|
||||
const e1 = PGF.readExpr('f')
|
||||
expect(e1).toBeInstanceOf(ExprFun)
|
||||
expect((e1 as ExprFun).name).toEqual('f')
|
||||
|
||||
const e2 = new ExprFun('f')
|
||||
const e3 = new ExprFun('g')
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).not.toEqual(e3)
|
||||
})
|
||||
|
||||
test('application 1', () => {
|
||||
const e1 = PGF.readExpr('f x y')
|
||||
expect(e1).toBeInstanceOf(ExprApp)
|
||||
expect((e1 as ExprApp).arg).toEqual(new ExprFun('y'))
|
||||
|
||||
const e2 = new ExprApp(
|
||||
new ExprApp(
|
||||
new ExprFun('f'),
|
||||
new ExprFun('x')
|
||||
), new ExprFun('y')
|
||||
)
|
||||
expect(e1).toEqual(e2)
|
||||
})
|
||||
|
||||
test('application 2', () => {
|
||||
const e1 = PGF.readExpr('f (g x)')
|
||||
const e2 = new ExprApp(
|
||||
new ExprFun('f'),
|
||||
new ExprApp(
|
||||
new ExprFun('g'),
|
||||
new ExprFun('x')
|
||||
)
|
||||
)
|
||||
expect(e1).toEqual(e2)
|
||||
})
|
||||
|
||||
test('application 3', () => {
|
||||
const e1 = PGF.readExpr('f {g x}')
|
||||
const e2 = new ExprApp(
|
||||
new ExprFun('f'),
|
||||
new ExprImplArg(
|
||||
new ExprApp(
|
||||
new ExprFun('g'),
|
||||
new ExprFun('x')
|
||||
)
|
||||
)
|
||||
)
|
||||
expect(e1).toEqual(e2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('variables', () => {
|
||||
test('meta 1', () => {
|
||||
const e1 = PGF.readExpr('?')
|
||||
expect(e1).toBeInstanceOf(ExprMeta)
|
||||
const e2 = new ExprMeta()
|
||||
const e3 = new ExprMeta(0)
|
||||
const e4 = new ExprMeta(1)
|
||||
expect(e1).toEqual(e2)
|
||||
expect(e1).toEqual(e3)
|
||||
expect(e1).not.toEqual(e4)
|
||||
})
|
||||
|
||||
test('meta 2', () => {
|
||||
const e1 = PGF.readExpr('?42')
|
||||
const e2 = new ExprMeta(42)
|
||||
expect(e1).toEqual(e2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user