From 8f2da8f8db0bfd6efc8d71724eead4d341ade270 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Wed, 17 Mar 2021 10:21:48 +0100 Subject: [PATCH] A more... pragmatic DefaultPointer --- .../javascript/packages/core/src/annotated.ts | 3 +- .../javascript/packages/core/src/bytes.ts | 3 +- .../packages/core/src/dictionary.ts | 3 +- .../javascript/packages/core/src/float.ts | 3 +- .../javascript/packages/core/src/fromjs.ts | 3 +- .../javascript/packages/core/src/is.ts | 2 +- .../javascript/packages/core/src/pointer.ts | 33 ++++++++ .../javascript/packages/core/src/record.ts | 3 +- .../javascript/packages/core/src/runtime.ts | 1 + .../javascript/packages/core/src/strip.ts | 3 +- .../javascript/packages/core/src/values.ts | 3 +- .../packages/core/test/codec.test.ts | 76 +++++++++++-------- .../packages/core/test/reader.test.ts | 15 ++-- .../packages/core/test/test-utils.ts | 28 ------- 14 files changed, 103 insertions(+), 76 deletions(-) create mode 100644 implementations/javascript/packages/core/src/pointer.ts diff --git a/implementations/javascript/packages/core/src/annotated.ts b/implementations/javascript/packages/core/src/annotated.ts index 8f18a94..d26333b 100644 --- a/implementations/javascript/packages/core/src/annotated.ts +++ b/implementations/javascript/packages/core/src/annotated.ts @@ -1,9 +1,10 @@ import { Encoder } from "./encoder"; import { Tag } from "./constants"; import { AsPreserve, PreserveOn } from "./symbols"; -import { DefaultPointer, Value } from "./values"; +import { Value } from "./values"; import { is, isAnnotated, IsPreservesAnnotated } from "./is"; import { stringify } from "./text"; +import { DefaultPointer } from "./pointer"; export interface Position { line?: number; diff --git a/implementations/javascript/packages/core/src/bytes.ts b/implementations/javascript/packages/core/src/bytes.ts index 2bd555a..7af797d 100644 --- a/implementations/javascript/packages/core/src/bytes.ts +++ b/implementations/javascript/packages/core/src/bytes.ts @@ -1,7 +1,8 @@ import { Tag } from './constants'; import { AsPreserve, PreserveOn } from './symbols'; import { Encoder, Preservable } from './encoder'; -import { DefaultPointer, Value } from './values'; +import { Value } from './values'; +import { DefaultPointer } from './pointer'; const textEncoder = new TextEncoder(); const textDecoder = new TextDecoder(); diff --git a/implementations/javascript/packages/core/src/dictionary.ts b/implementations/javascript/packages/core/src/dictionary.ts index a639610..fc4715c 100644 --- a/implementations/javascript/packages/core/src/dictionary.ts +++ b/implementations/javascript/packages/core/src/dictionary.ts @@ -3,9 +3,10 @@ import { Tag } from "./constants"; import { FlexMap, FlexSet, _iterMap } from "./flex"; import { PreserveOn } from "./symbols"; import { stringify } from "./text"; -import { DefaultPointer, Value } from "./values"; +import { Value } from "./values"; import { Bytes } from './bytes'; import { fromJS } from "./fromjs"; +import { DefaultPointer } from "./pointer"; export type DictionaryType = 'Dictionary' | 'Set'; export const DictionaryType = Symbol.for('DictionaryType'); diff --git a/implementations/javascript/packages/core/src/float.ts b/implementations/javascript/packages/core/src/float.ts index b636a6d..db1cfd3 100644 --- a/implementations/javascript/packages/core/src/float.ts +++ b/implementations/javascript/packages/core/src/float.ts @@ -1,7 +1,8 @@ import { Encoder, Preservable } from "./encoder"; import { Tag } from "./constants"; import { AsPreserve, PreserveOn } from "./symbols"; -import { DefaultPointer, Value } from "./values"; +import { Value } from "./values"; +import { DefaultPointer } from "./pointer"; export type FloatType = 'Single' | 'Double'; export const FloatType = Symbol.for('FloatType'); diff --git a/implementations/javascript/packages/core/src/fromjs.ts b/implementations/javascript/packages/core/src/fromjs.ts index 1e035f3..b8d4026 100644 --- a/implementations/javascript/packages/core/src/fromjs.ts +++ b/implementations/javascript/packages/core/src/fromjs.ts @@ -1,7 +1,8 @@ +import { DefaultPointer } from "./pointer"; import { Bytes } from "./bytes"; import { Record, Tuple } from "./record"; import { AsPreserve } from "./symbols"; -import { DefaultPointer, Value } from "./values"; +import { Value } from "./values"; export function fromJS(x: any): Value { switch (typeof x) { diff --git a/implementations/javascript/packages/core/src/is.ts b/implementations/javascript/packages/core/src/is.ts index 8ed453c..36a0ff0 100644 --- a/implementations/javascript/packages/core/src/is.ts +++ b/implementations/javascript/packages/core/src/is.ts @@ -1,4 +1,4 @@ -import type { DefaultPointer } from "./values.js"; +import type { DefaultPointer } from "./pointer.js"; import type { Annotated } from "./annotated.js"; export const IsPreservesAnnotated = Symbol.for('IsPreservesAnnotated'); diff --git a/implementations/javascript/packages/core/src/pointer.ts b/implementations/javascript/packages/core/src/pointer.ts new file mode 100644 index 0000000..7306c19 --- /dev/null +++ b/implementations/javascript/packages/core/src/pointer.ts @@ -0,0 +1,33 @@ +import type { Encoder } from "./encoder"; +import type { TypedDecoder } from "./decoder"; +import type { Value } from "./values"; + +import { strip } from "./strip"; + +export class DefaultPointer { + v: Value; + + constructor(v: Value) { + this.v = v; + } + + equals(other: any, is: (a: any, b: any) => boolean) { + return Object.is(other.constructor, this.constructor) && is(this.v, other.v); + } + + asPreservesText(): string { + return '#!' + this.v.asPreservesText(); + } +} + +export function readDefaultPointer(v: Value): DefaultPointer { + return new DefaultPointer(strip(v)); +} + +export function decodeDefaultPointer(d: TypedDecoder): DefaultPointer { + return readDefaultPointer(d.next()); +} + +export function encodeDefaultPointer(e: Encoder, w: DefaultPointer): void { + e.push(w.v); +} diff --git a/implementations/javascript/packages/core/src/record.ts b/implementations/javascript/packages/core/src/record.ts index 3a4b210..b7d84e3 100644 --- a/implementations/javascript/packages/core/src/record.ts +++ b/implementations/javascript/packages/core/src/record.ts @@ -1,5 +1,6 @@ +import { DefaultPointer } from "./pointer"; import { is } from "./is"; -import { DefaultPointer, Value } from "./values"; +import { Value } from "./values"; export type Tuple = Array | [T]; diff --git a/implementations/javascript/packages/core/src/runtime.ts b/implementations/javascript/packages/core/src/runtime.ts index 654ac42..30dbf79 100644 --- a/implementations/javascript/packages/core/src/runtime.ts +++ b/implementations/javascript/packages/core/src/runtime.ts @@ -9,6 +9,7 @@ export * from './float'; export * from './fold'; export * from './fromjs'; export * from './is'; +export * from './pointer'; export * from './reader'; export * from './record'; export * from './strip'; diff --git a/implementations/javascript/packages/core/src/strip.ts b/implementations/javascript/packages/core/src/strip.ts index 0fbf446..73dba52 100644 --- a/implementations/javascript/packages/core/src/strip.ts +++ b/implementations/javascript/packages/core/src/strip.ts @@ -1,7 +1,8 @@ -import { DefaultPointer, Value } from "./values"; +import { Value } from "./values"; import { Annotated } from "./annotated"; import { Record, Tuple } from "./record"; import { Set, Dictionary } from "./dictionary"; +import type { DefaultPointer } from "./pointer"; export function unannotate(v: Value): Value { return Annotated.isAnnotated(v) ? v.item : v; diff --git a/implementations/javascript/packages/core/src/values.ts b/implementations/javascript/packages/core/src/values.ts index 50b675c..4e38593 100644 --- a/implementations/javascript/packages/core/src/values.ts +++ b/implementations/javascript/packages/core/src/values.ts @@ -4,8 +4,7 @@ import type { Bytes } from './bytes'; import type { DoubleFloat, SingleFloat } from './float'; import type { Annotated } from './annotated'; import type { Set, Dictionary } from './dictionary'; - -export type DefaultPointer = never; +import type { DefaultPointer } from './pointer'; export type Value = | Atom diff --git a/implementations/javascript/packages/core/test/codec.test.ts b/implementations/javascript/packages/core/test/codec.test.ts index 63a2dd6..70678bf 100644 --- a/implementations/javascript/packages/core/test/codec.test.ts +++ b/implementations/javascript/packages/core/test/codec.test.ts @@ -11,19 +11,21 @@ import { Constants, TypedDecoder, Encoder, + DefaultPointer, + decodeDefaultPointer, + encodeDefaultPointer, } from '../src/index'; const { Tag } = Constants; import './test-utils'; -import { decodePointer, encodePointer, Pointer } from './test-utils'; import * as fs from 'fs'; const _discard = Symbol.for('discard'); const _capture = Symbol.for('capture'); const _observe = Symbol.for('observe'); -const Discard = Record.makeConstructor<{}, Pointer>()(_discard, []); -const Capture = Record.makeConstructor<{pattern: Value}, Pointer>()(_capture, ['pattern']); -const Observe = Record.makeConstructor<{pattern: Value}, Pointer>()(_observe, ['pattern']); +const Discard = Record.makeConstructor<{}, DefaultPointer>()(_discard, []); +const Capture = Record.makeConstructor<{pattern: Value}, DefaultPointer>()(_capture, ['pattern']); +const Observe = Record.makeConstructor<{pattern: Value}, DefaultPointer>()(_observe, ['pattern']); describe('record constructors', () => { it('should have constructorInfo', () => { @@ -152,52 +154,61 @@ describe('encoding and decoding pointers', () => { describe('common test suite', () => { const samples_bin = fs.readFileSync(__dirname + '/../../../../../tests/samples.bin'); - const samples = decodeWithAnnotations(samples_bin, { decodePointer }); + const samples = decodeWithAnnotations(samples_bin, { decodePointer: decodeDefaultPointer }); - const TestCases = Record.makeConstructor<{cases: Dictionary, Pointer>}>()(Symbol.for('TestCases'), ['cases']); + const TestCases = Record.makeConstructor<{ + cases: Dictionary, DefaultPointer> + }>()(Symbol.for('TestCases'), ['cases']); type TestCases = ReturnType; function DS(bs: Bytes) { - return decode(bs, { decodePointer }); + return decode(bs, { decodePointer: decodeDefaultPointer }); } function D(bs: Bytes) { - return decodeWithAnnotations(bs, { decodePointer }); + return decodeWithAnnotations(bs, { decodePointer: decodeDefaultPointer }); } - function E(v: Value) { - return encodeWithAnnotations(v, { encodePointer }); + function E(v: Value) { + return encodeWithAnnotations(v, { encodePointer: encodeDefaultPointer }); } interface ExpectedValues { - [testName: string]: { value: Value } | { forward: Value, back: Value }; + [testName: string]: ({ + value: Value; + } | { + forward: Value; + back: Value; + }); } const expectedValues: ExpectedValues = { - annotation1: { forward: annotate(9, "abc"), + annotation1: { forward: annotate(9, "abc"), back: 9 }, - annotation2: { forward: annotate([[], annotate([], "x")], "abc", "def"), + annotation2: { forward: annotate([[], annotate([], "x")], + "abc", + "def"), back: [[], []] }, - annotation3: { forward: annotate(5, - annotate(2, 1), - annotate(4, 3)), + annotation3: { forward: annotate(5, + annotate(2, 1), + annotate(4, 3)), back: 5 }, annotation5: { - forward: annotate( + forward: annotate( Record(Symbol.for('R'), - [annotate(Symbol.for('f'), - Symbol.for('af'))]), + [annotate(Symbol.for('f'), + Symbol.for('af'))]), Symbol.for('ar')), - back: Record, any>(Symbol.for('R'), [Symbol.for('f')]) + back: Record, any>(Symbol.for('R'), [Symbol.for('f')]) }, annotation6: { - forward: Record, any>( - annotate(Symbol.for('R'), - Symbol.for('ar')), - [annotate(Symbol.for('f'), - Symbol.for('af'))]), + forward: Record, any>( + annotate(Symbol.for('R'), + Symbol.for('ar')), + [annotate(Symbol.for('f'), + Symbol.for('af'))]), back: Record(Symbol.for('R'), [Symbol.for('f')]) }, annotation7: { - forward: annotate([], Symbol.for('a'), Symbol.for('b'), Symbol.for('c')), + forward: annotate([], Symbol.for('a'), Symbol.for('b'), Symbol.for('c')), back: [] }, list1: { @@ -214,7 +225,11 @@ describe('common test suite', () => { type Variety = 'normal' | 'nondeterministic' | 'decode'; - function runTestCase(variety: Variety, tName: string, binaryForm: Bytes, annotatedTextForm: Value) { + function runTestCase(variety: Variety, + tName: string, + binaryForm: Bytes, + annotatedTextForm: Value) + { describe(tName, () => { const textForm = strip(annotatedTextForm); const {forward, back} = (function () { @@ -241,10 +256,11 @@ describe('common test suite', () => { }); } - const tests = peel(TestCases._.cases(peel(samples) as TestCases)) as Dictionary, Pointer>; - tests.forEach((t0: Value, tName0: Value) => { + const tests = (peel(TestCases._.cases(peel(samples) as TestCases)) as + Dictionary, DefaultPointer>); + tests.forEach((t0: Value, tName0: Value) => { const tName = Symbol.keyFor(strip(tName0) as symbol)!; - const t = peel(t0) as Record; + const t = peel(t0) as Record; switch (t.label) { case Symbol.for('Test'): runTestCase('normal', tName, strip(t[0]) as Bytes, t[1]); diff --git a/implementations/javascript/packages/core/test/reader.test.ts b/implementations/javascript/packages/core/test/reader.test.ts index 35b6568..03539cb 100644 --- a/implementations/javascript/packages/core/test/reader.test.ts +++ b/implementations/javascript/packages/core/test/reader.test.ts @@ -1,6 +1,5 @@ -import { Bytes, Decoder, encode, Reader } from '../src/index'; +import { Bytes, decodeDefaultPointer, Decoder, encode, encodeDefaultPointer, readDefaultPointer, Reader } from '../src/index'; import './test-utils'; -import { decodePointer, encodePointer, readPointer } from './test-utils'; import * as fs from 'fs'; @@ -9,25 +8,25 @@ describe('reading common test suite', () => { const samples_pr = fs.readFileSync(__dirname + '/../../../../../tests/samples.pr', 'utf-8'); it('should read equal to decoded binary without annotations', () => { - const s1 = new Reader(samples_pr, { decodePointer: readPointer, includeAnnotations: false }).next(); + const s1 = new Reader(samples_pr, { decodePointer: readDefaultPointer, includeAnnotations: false }).next(); const s2 = new Decoder(samples_bin, { includeAnnotations: false }).withPointerDecoder( - decodePointer, + decodeDefaultPointer, d => d.next()); expect(s1).is(s2); }); it('should read equal to decoded binary with annotations', () => { - const s1 = new Reader(samples_pr, { decodePointer: readPointer, includeAnnotations: true }).next(); + const s1 = new Reader(samples_pr, { decodePointer: readDefaultPointer, includeAnnotations: true }).next(); const s2 = new Decoder(samples_bin, { includeAnnotations: true }).withPointerDecoder( - decodePointer, + decodeDefaultPointer, d => d.next()); expect(s1).is(s2); }); it('should read and encode back to binary with annotations', () => { - const s = new Reader(samples_pr, { decodePointer: readPointer, includeAnnotations: true }).next(); + const s = new Reader(samples_pr, { decodePointer: readDefaultPointer, includeAnnotations: true }).next(); const bs = Bytes.toIO(encode(s, { - encodePointer, + encodePointer: encodeDefaultPointer, includeAnnotations: true, canonical: true, })); diff --git a/implementations/javascript/packages/core/test/test-utils.ts b/implementations/javascript/packages/core/test/test-utils.ts index f6b1655..a90469a 100644 --- a/implementations/javascript/packages/core/test/test-utils.ts +++ b/implementations/javascript/packages/core/test/test-utils.ts @@ -34,31 +34,3 @@ expect.extend({ } } }); - -export class Pointer { - v: Value; - - constructor(v: Value) { - this.v = v; - } - - equals(other: any, is: (a: any, b: any) => boolean) { - return Object.is(other.constructor, this.constructor) && is(this.v, other.v); - } - - asPreservesText(): string { - return '#!' + this.v.asPreservesText(); - } -} - -export function readPointer(v: Value): Pointer { - return new Pointer(strip(v)); -} - -export function decodePointer(d: TypedDecoder): Pointer { - return readPointer(d.next()); -} - -export function encodePointer(e: Encoder, w: Pointer): void { - e.push(w.v); -}