Attenuator, for experimenting with client/server

This commit is contained in:
Tony Garnock-Jones 2021-03-05 21:37:58 +01:00
parent 4b7fd6ce88
commit 1b120512a8
4 changed files with 24 additions and 11 deletions

View File

@ -1,4 +1,4 @@
import { Dictionary, IdentitySet, Record, Tuple, Value, is, IdentityMap } from 'preserves';
import { IdentitySet, Value } from 'preserves';
import { Attenuation, runRewrites } from './rewrite.js';
import { queueTask } from './task.js';

View File

@ -27,7 +27,7 @@ export const PDiscard = Record.makeConstructor<{}, never>()(
_PDiscard, []);
export const _PBind = Symbol.for('bind');
export const PBind = Record.makeConstructor<{name: string, pattern: Pattern}, never>()(
export const PBind = Record.makeConstructor<{name: symbol, pattern: Pattern}, never>()(
_PBind, ['name', 'pattern']);
export const _PAnd = Symbol.for('and');
@ -49,14 +49,14 @@ export const PCompound =
export type Pattern =
| Record<typeof _PDiscard, [], never>
| Record<typeof _PBind, [string, Pattern], never>
| Record<typeof _PBind, [symbol, Pattern], never>
| Record<typeof _PAnd, [Pattern[]], never>
| Record<typeof _PNot, [Pattern], never>
| Record<typeof _Lit, [Value<never>], never>
| Record<typeof _PCompound, [ConstructorSpec, Dictionary<Pattern, never>], never>;
export const _TRef = Symbol.for('ref');
export const TRef = Record.makeConstructor<{name: string}, never>()(
export const TRef = Record.makeConstructor<{name: symbol}, never>()(
_TRef, ['name']);
export const _TCompound = Symbol.for('compound');
@ -65,7 +65,7 @@ export const TCompound =
_TCompound, ['ctor', 'members']);
export type Template =
| Record<typeof _TRef, [string], never>
| Record<typeof _TRef, [symbol], never>
| Record<typeof _Lit, [Value<never>], never>
| Record<typeof _TCompound, [ConstructorSpec, Dictionary<Template, never>], never>;
@ -78,7 +78,7 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
return true;
case _PBind:
if (walk(PBind._.pattern(p), v)) {
bindings[PBind._.name(p)] = v;
bindings[PBind._.name(p).asPreservesText()] = v;
return true;
}
return false;
@ -138,8 +138,9 @@ export function instantiate(t: Template, b: Bindings): Assertion {
function walk(t: Template): Assertion {
switch (t.label) {
case _TRef: {
const v = b[TRef._.name(t)];
if (v === void 0) throw new Error(`Unbound reference: ${TRef._.name(t)}`);
const n = TRef._.name(t).asPreservesText()
const v = b[n];
if (v === void 0) throw new Error(`Unbound reference: ${n}`);
return v;
}
case _Lit:
@ -207,8 +208,10 @@ export function runRewrites(a: Attenuation | undefined, v: Assertion): Assertion
return v;
}
const _a = Symbol.for('a');
export function rfilter(... patterns: Pattern[]): RewriteStage {
return patterns.map(p => ({ pattern: PBind('a', p), template: TRef('a') }));
return patterns.map(p => ({ pattern: PBind(_a, p), template: TRef(_a) }));
}
export function attenuate(ref: Ref, ... a: Attenuation): Ref {

View File

@ -6,11 +6,11 @@ import { Bytes, Dictionary } from 'preserves';
async function main() {
const m1 = await mint('hello world', new Bytes(KEY_LENGTH));
console.log(m1.asPreservesText());
const m2 = await attenuate(m1, Rewrite(RW.PBind('a',
const m2 = await attenuate(m1, Rewrite(RW.PBind(Symbol.for('a'),
RW.PCompound(RW.CRec(Symbol.for('says'), 2),
new Dictionary<RW.Pattern, never>([
[0, RW.Lit('Tony')]]))),
RW.TRef('a')));
RW.TRef(Symbol.for('a'))));
console.log(m2.asPreservesText());
console.log('should be true:', await validate(m1, new Bytes(KEY_LENGTH)));
console.log('should be true:', await validate(m2, new Bytes(KEY_LENGTH)));

10
src/tools/attenuate.ts Normal file
View File

@ -0,0 +1,10 @@
import { Bytes, Reader } from 'preserves';
import { attenuate, Caveat, sturdyDecode, sturdyEncode, SturdyRef } from '../sturdy.js';
const [ base, pat ] = process.argv.slice(2);
const baseCap = sturdyDecode(Bytes.fromHex(base ?? '')) as SturdyRef;
const cs = new Reader(pat).next() as Array<Caveat>;
attenuate(baseCap, ... cs).then(derived => {
console.log(derived.asPreservesText());
console.log(sturdyEncode(derived).toHex());
});