A more... pragmatic DefaultPointer

This commit is contained in:
Tony Garnock-Jones 2021-03-17 10:21:48 +01:00
parent 12121128a6
commit 8f2da8f8db
14 changed files with 103 additions and 76 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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');

View File

@ -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');

View File

@ -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<T = DefaultPointer>(x: any): Value<T> {
switch (typeof x) {

View File

@ -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');

View File

@ -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<DefaultPointer>;
constructor(v: Value<DefaultPointer>) {
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>): DefaultPointer {
return new DefaultPointer(strip(v));
}
export function decodeDefaultPointer(d: TypedDecoder<DefaultPointer>): DefaultPointer {
return readDefaultPointer(d.next());
}
export function encodeDefaultPointer(e: Encoder<DefaultPointer>, w: DefaultPointer): void {
e.push(w.v);
}

View File

@ -1,5 +1,6 @@
import { DefaultPointer } from "./pointer";
import { is } from "./is";
import { DefaultPointer, Value } from "./values";
import { Value } from "./values";
export type Tuple<T> = Array<T> | [T];

View File

@ -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';

View File

@ -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<T = DefaultPointer>(v: Value<T>): Value<T> {
return Annotated.isAnnotated<T>(v) ? v.item : v;

View File

@ -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<T = DefaultPointer> =
| Atom

View File

@ -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>}, Pointer>()(_capture, ['pattern']);
const Observe = Record.makeConstructor<{pattern: Value<Pointer>}, Pointer>()(_observe, ['pattern']);
const Discard = Record.makeConstructor<{}, DefaultPointer>()(_discard, []);
const Capture = Record.makeConstructor<{pattern: Value<DefaultPointer>}, DefaultPointer>()(_capture, ['pattern']);
const Observe = Record.makeConstructor<{pattern: Value<DefaultPointer>}, 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<Value<Pointer>, Pointer>}>()(Symbol.for('TestCases'), ['cases']);
const TestCases = Record.makeConstructor<{
cases: Dictionary<Value<DefaultPointer>, DefaultPointer>
}>()(Symbol.for('TestCases'), ['cases']);
type TestCases = ReturnType<typeof TestCases>;
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<Pointer>) {
return encodeWithAnnotations(v, { encodePointer });
function E(v: Value<DefaultPointer>) {
return encodeWithAnnotations(v, { encodePointer: encodeDefaultPointer });
}
interface ExpectedValues {
[testName: string]: { value: Value<Pointer> } | { forward: Value<Pointer>, back: Value<Pointer> };
[testName: string]: ({
value: Value<DefaultPointer>;
} | {
forward: Value<DefaultPointer>;
back: Value<DefaultPointer>;
});
}
const expectedValues: ExpectedValues = {
annotation1: { forward: annotate<Pointer>(9, "abc"),
annotation1: { forward: annotate<DefaultPointer>(9, "abc"),
back: 9 },
annotation2: { forward: annotate<Pointer>([[], annotate<Pointer>([], "x")], "abc", "def"),
annotation2: { forward: annotate<DefaultPointer>([[], annotate<DefaultPointer>([], "x")],
"abc",
"def"),
back: [[], []] },
annotation3: { forward: annotate<Pointer>(5,
annotate<Pointer>(2, 1),
annotate<Pointer>(4, 3)),
annotation3: { forward: annotate<DefaultPointer>(5,
annotate<DefaultPointer>(2, 1),
annotate<DefaultPointer>(4, 3)),
back: 5 },
annotation5: {
forward: annotate<Pointer>(
forward: annotate<DefaultPointer>(
Record<symbol, any>(Symbol.for('R'),
[annotate<Pointer>(Symbol.for('f'),
Symbol.for('af'))]),
[annotate<DefaultPointer>(Symbol.for('f'),
Symbol.for('af'))]),
Symbol.for('ar')),
back: Record<Value<Pointer>, any>(Symbol.for('R'), [Symbol.for('f')])
back: Record<Value<DefaultPointer>, any>(Symbol.for('R'), [Symbol.for('f')])
},
annotation6: {
forward: Record<Value<Pointer>, any>(
annotate<Pointer>(Symbol.for('R'),
Symbol.for('ar')),
[annotate<Pointer>(Symbol.for('f'),
Symbol.for('af'))]),
forward: Record<Value<DefaultPointer>, any>(
annotate<DefaultPointer>(Symbol.for('R'),
Symbol.for('ar')),
[annotate<DefaultPointer>(Symbol.for('f'),
Symbol.for('af'))]),
back: Record<symbol, any>(Symbol.for('R'), [Symbol.for('f')])
},
annotation7: {
forward: annotate<Pointer>([], Symbol.for('a'), Symbol.for('b'), Symbol.for('c')),
forward: annotate<DefaultPointer>([], 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<Pointer>) {
function runTestCase(variety: Variety,
tName: string,
binaryForm: Bytes,
annotatedTextForm: Value<DefaultPointer>)
{
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<Value<Pointer>, Pointer>;
tests.forEach((t0: Value<Pointer>, tName0: Value<Pointer>) => {
const tests = (peel(TestCases._.cases(peel(samples) as TestCases)) as
Dictionary<Value<DefaultPointer>, DefaultPointer>);
tests.forEach((t0: Value<DefaultPointer>, tName0: Value<DefaultPointer>) => {
const tName = Symbol.keyFor(strip(tName0) as symbol)!;
const t = peel(t0) as Record<symbol, any, Pointer>;
const t = peel(t0) as Record<symbol, any, DefaultPointer>;
switch (t.label) {
case Symbol.for('Test'):
runTestCase('normal', tName, strip(t[0]) as Bytes, t[1]);

View File

@ -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,
}));

View File

@ -34,31 +34,3 @@ expect.extend({
}
}
});
export class Pointer {
v: Value<Pointer>;
constructor(v: Value<Pointer>) {
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>): Pointer {
return new Pointer(strip(v));
}
export function decodePointer(d: TypedDecoder<Pointer>): Pointer {
return readPointer(d.next());
}
export function encodePointer(e: Encoder<Pointer>, w: Pointer): void {
e.push(w.v);
}