From 90a6e2f41a80d191ed5ecfa2015cd71eea83ae39 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 13 Dec 2021 20:20:31 +0100 Subject: [PATCH] Adapt to syndicate-protocols changes --- packages/core/src/runtime/pattern.ts | 149 +++++++++++++++++------- packages/core/src/runtime/quasivalue.ts | 30 ++--- packages/core/src/runtime/rewrite.ts | 114 +++++++----------- packages/core/src/runtime/skeleton.ts | 11 +- packages/timer/src/index.ts | 4 +- packages/ws-relay/src/index.ts | 8 +- 6 files changed, 178 insertions(+), 138 deletions(-) diff --git a/packages/core/src/runtime/pattern.ts b/packages/core/src/runtime/pattern.ts index 8a1a431..91339b9 100644 --- a/packages/core/src/runtime/pattern.ts +++ b/packages/core/src/runtime/pattern.ts @@ -1,7 +1,7 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones -import { canonicalString, is, KeyedDictionary, Record, RecordConstructorInfo, Value } from '@preserves/core'; +import { canonicalString, Dictionary, is, Record, RecordConstructorInfo, Value } from '@preserves/core'; import { AnyValue, Ref } from './actor.js'; import * as P from '../gen/dataspacePatterns.js'; @@ -24,9 +24,9 @@ export function classOfValue(v: any): Shape | null { export function classOfCtor(v: P.DCompound): Shape { switch (v._variant) { case 'rec': - return canonicalString(v.ctor.label) + '/' + v.ctor.arity; + return canonicalString(v.label) + '/' + v.fields.length; case 'arr': - return '' + v.ctor.arity; + return '' + v.items.length; case 'dict': return '{}'; } @@ -59,14 +59,20 @@ export function analysePattern(p: P.Pattern): PatternAnalysis { }; const path: Path = []; + function walkKey(p: P.Pattern, key: AnyValue) { + path.push(key); + walk(p); + path.pop(); + } + function walk(p: P.Pattern) { switch (p._variant) { case 'DCompound': - p.value.members.forEach((v, k) => { - path.push(k); - walk(v); - path.pop(); - }); + switch (p.value._variant) { + case 'rec': p.value.fields.forEach(walkKey); break; + case 'arr': p.value.items.forEach(walkKey); break; + case 'dict': p.value.entries.forEach(walkKey); break; + } break; case 'DBind': result.capturePaths.push(path.slice()); @@ -76,7 +82,7 @@ export function analysePattern(p: P.Pattern): PatternAnalysis { break; case 'DLit': result.constPaths.push(path.slice()); - result.constValues.push(p.value.value); + result.constValues.push(P.fromAnyAtom(p.value.value)); break; } } @@ -102,10 +108,21 @@ export function match(p: P.Pattern, v: AnyValue): Array | false { const pcls = classOfCtor(p.value); const vcls = classOfValue(v); if (pcls !== vcls) return false; - for (const [stepIndex, pp] of p.value.members.entries()) { - const vv = step(v, stepIndex); - if (vv === void 0) return false; - if (!walk(pp, vv)) return false; + let items: Array; + switch (p.value._variant) { + case 'dict': + for (const [stepIndex, pp] of p.value.entries.entries()) { + const vv = step(v, stepIndex); + if (vv === void 0 || !walk(pp, vv)) return false; + } + return true; + case 'rec': items = p.value.fields; break; + case 'arr': items = p.value.items; break; + } + let index = 0; + for (const pp of items) { + const vv = step(v, index++); + if (vv === void 0 || !walk(pp, vv)) return false; } return true; } @@ -121,11 +138,16 @@ export function isCompletelyConcrete(p: P.Pattern): boolean { case 'DBind': return false; case 'DDiscard': return false; case 'DLit': return true; - case 'DCompound': - for (const pp of p.value.members.values()) { - if (!walk(pp)) return false; + case 'DCompound': switch (p.value._variant) { + case 'rec': return p.value.fields.every(isCompletelyConcrete); + case 'arr': return p.value.items.every(isCompletelyConcrete); + case 'dict': { + for (const pp of p.value.entries.values()) { + if (!walk(pp)) return false; + } + return true; } - return true; + } } } return walk(p); @@ -137,11 +159,19 @@ export function withoutCaptures(p: P.Pattern): P.Pattern { case 'DBind': return walk(p.value.pattern); case 'DDiscard': return p; case 'DLit': return p; - case 'DCompound': return P.Pattern.DCompound({ - _variant: p.value._variant, - ctor: p.value.ctor, - members: p.value.members.mapEntries(e => [e[0], walk(e[1])]), - } as P.DCompound); + case 'DCompound': + switch (p.value._variant) { + case 'rec': + return P.Pattern.DCompound(P.DCompound.rec({ + label: p.value.label, + fields: p.value.fields.map(walk), + })); + case 'arr': + return P.Pattern.DCompound(P.DCompound.arr(p.value.items.map(walk))); + case 'dict': + return P.Pattern.DCompound(P.DCompound.dict(p.value.entries.mapEntries( + e => [e[0], walk(e[1])]))); + } } } return walk(p); @@ -161,38 +191,67 @@ export function discard(): P.Pattern { export const _ = discard(); export function lit(v: AnyValue): P.Pattern { - return P.Pattern.DLit(P.DLit(v)); + if (Array.isArray(v)) { + if ('label' in v) { + return P.Pattern.DCompound(P.DCompound.rec({ + label: v.label, + fields: v.map(lit), + })); + } else { + return P.Pattern.DCompound(P.DCompound.arr(v.map(lit))); + } + } else if (Map.isMap(v)) { + return P.Pattern.DCompound(P.DCompound.dict(v.mapEntries( + e => [e[0], lit(e[1])]))); + } else if (Set.isSet(v)) { + throw new Error("Cannot express literal set in pattern"); + } else { + return P.Pattern.DLit(P.DLit(P.asAnyAtom(v))); + } } -function indexedMembers(items: P.Pattern[]): KeyedDictionary { - const members = new KeyedDictionary(); - items.forEach((p, i) => { - if (!is(p, _)) members.set(i, p); - }); - return members; +export function drop_lit(p: P.Pattern): AnyValue | null { + const e = new Error(); + function walk(p: P.Pattern): AnyValue { + switch (p._variant) { + case 'DCompound': + switch (p.value._variant) { + case 'rec': { + const v = [] as unknown as Record; + v.label = p.value.label; + p.value.fields.forEach(tt => v.push(walk(tt))); + return v; + } + case 'arr': + return p.value.items.map(walk); + case 'dict': { + const v = new Dictionary(); + p.value.entries.forEach((pp, key) => v.set(key, walk(pp))); + return v; + } + } + case 'DLit': + return P.fromAnyAtom(p.value.value); + default: + throw e; + } + } + try { + return walk(p); + } catch (ee) { + if (ee == e) return null; + throw ee; + } } export function rec(label: AnyValue, ... fields: P.Pattern[]): P.Pattern { - return P.Pattern.DCompound(P.DCompound.rec({ - ctor: P.CRec({ - label, - arity: fields.length, - }), - members: indexedMembers(fields), - })); + return P.Pattern.DCompound(P.DCompound.rec({ label, fields })); } export function arr(... patterns: P.Pattern[]): P.Pattern { - return P.Pattern.DCompound(P.DCompound.arr({ - ctor: P.CArr(patterns.length), - members: indexedMembers(patterns), - })); + return P.Pattern.DCompound(P.DCompound.arr(patterns)); } export function dict(... entries: [AnyValue, P.Pattern][]): P.Pattern { - const members = new KeyedDictionary(); - entries.forEach(([k, p]) => { - if (!is(p, _)) members.set(k, p); - }); - return P.Pattern.DCompound(P.DCompound.dict({ ctor: P.CDict(), members })); + return P.Pattern.DCompound(P.DCompound.dict(new Dictionary(entries))); } diff --git a/packages/core/src/runtime/quasivalue.ts b/packages/core/src/runtime/quasivalue.ts index aa89b2a..c598101 100644 --- a/packages/core/src/runtime/quasivalue.ts +++ b/packages/core/src/runtime/quasivalue.ts @@ -2,7 +2,7 @@ /// SPDX-FileCopyrightText: Copyright © 2021 Tony Garnock-Jones import { AnyValue, Ref } from './actor.js'; -import { Pattern } from '../gen/dataspacePatterns.js'; +import { Pattern, toPattern } from '../gen/dataspacePatterns.js'; import * as P from './pattern.js'; import { Value, RecordConstructorInfo, is, Record } from '@preserves/core'; import { Meta, Type, GenType } from '@preserves/schema'; @@ -49,6 +49,16 @@ export function lit(value: AnyValue): QuasiValue { lit.quasiValue = (q: QuasiValue) => rec(Symbol.for('lit'), q); +export function drop_lit(patValue: AnyValue): AnyValue | null; +export function drop_lit(patValue: AnyValue, parser: (v: AnyValue) => R): R | null; +export function drop_lit(patValue: AnyValue, parser?: (v: AnyValue) => R): any { + const pat = toPattern(patValue); + if (pat === void 0) return null; + const val = P.drop_lit(pat); + if (val === null) return null; + return parser === void 0 ? val : parser(val); +} + export function rec(label: AnyValue, ... items: QuasiValue[]): QuasiValue { const literals = items.flatMap(i => i.type === 'lit' ? [i.value] : []); if (literals.length === items.length) { @@ -76,18 +86,12 @@ export function quote(quoted: QuasiValue): QuasiValue { case 'bind': return quote(bind.quasiValue(quoted.inner)); case 'discard': return quote(discard.quasiValue()); case 'lit': return rec(Symbol.for('lit'), lit(quoted.value)); - case 'arr': return rec( - Symbol.for('compound'), - rec(Symbol.for('arr'), lit(quoted.items.length)), - dict(... quoted.items.map((qq, i) => [i, quote(qq)] as [AnyValue, QuasiValue]))); - case 'rec': return rec( - Symbol.for('compound'), - rec(Symbol.for('rec'), lit(quoted.label), lit(quoted.items.length)), - dict(... quoted.items.map((qq, i) => [i, quote(qq)] as [AnyValue, QuasiValue]))); - case 'dict': return rec( - Symbol.for('compound'), - rec(Symbol.for('dict')), - dict(... quoted.entries.map(([k, qq]) => [k, quote(qq)] as [AnyValue, QuasiValue]))); + case 'arr': return rec(Symbol.for('arr'), arr( + ... quoted.items.map(quote))); + case 'rec': return rec(Symbol.for('rec'), lit(quoted.label), arr( + ... quoted.items.map(quote))); + case 'dict': return rec(Symbol.for('dict'), dict( + ... quoted.entries.map(([k, qq]) => [k, quote(qq)] as [AnyValue, QuasiValue]))); case 'unquote': return quoted.unquoted; } } diff --git a/packages/core/src/runtime/rewrite.ts b/packages/core/src/runtime/rewrite.ts index d5fb823..0de62cd 100644 --- a/packages/core/src/runtime/rewrite.ts +++ b/packages/core/src/runtime/rewrite.ts @@ -9,17 +9,12 @@ import { SturdyValue } from "../transport/sturdy.js"; import { Alts, Attenuation, - CArr, - CDict, - CRec, Caveat, - ConstructorSpec, Lit, PAnd, PAtom, PBind, PCompound, - PCompoundMembers, PDiscard, PNot, PEmbedded, @@ -72,36 +67,35 @@ export function match(p: Pattern, v: Assertion): Bindings | null { } case 'Lit': return is(p.value.value, v); - case 'PCompound': { - const ctor = p.value.ctor; - const members = p.value.members; - switch (ctor._variant) { - case 'CRec': - if (!Record.isRecord, Ref>(v)) return false; - if (!is(ctor.value.label, v.label)) return false; - if (ctor.value.arity !== v.length) return false; - for (const [key, pp] of members) { - if (typeof key !== 'number') return false; - if (!walk(pp, v[key])) return false; - } - return true; - case 'CArr': - if (!Array.isArray(v)) return false; - if ('label' in v) return false; - if (ctor.value.arity !== v.length) return false; - for (const [key, pp] of members) { - if (typeof key !== 'number') return false; - if (!walk(pp, v[key])) return false; - } - return true; - case 'CDict': - if (!Dictionary.isDictionary(v)) return false; - for (const [key, pp] of members) { - const vv = v.get(key); - if (vv === void 0) return false; - if (!walk(pp, vv)) return false; - } - return true; + case 'PCompound': switch (p.value._variant) { + case 'rec': { + if (!Record.isRecord, Ref>(v)) return false; + if (!is(p.value.label, v.label)) return false; + if (p.value.fields.length !== v.length) return false; + let index = 0; + for (const pp of p.value.fields) { + if (!walk(pp, v[index++])) return false; + } + return true; + } + case 'arr': { + if (!Array.isArray(v)) return false; + if ('label' in v) return false; + if (p.value.items.length !== v.length) return false; + let index = 0; + for (const pp of p.value.items) { + if (!walk(pp, v[index++])) return false; + } + return true; + } + case 'dict':{ + if (!Dictionary.isDictionary(v)) return false; + for (const [key, pp] of p.value.entries.entries()) { + const vv = v.get(key); + if (vv === void 0) return false; + if (!walk(pp, vv)) return false; + } + return true; } } default: @@ -132,36 +126,22 @@ export function instantiate(t: Template, b: Bindings): Assertion { } case 'Lit': return t.value.value; - case 'TCompound': { - const ctor = t.value.ctor; - const members = t.value.members; - switch (ctor._variant) { - case 'CRec': { + case 'TCompound': + switch (t.value._variant) { + case 'rec': { const v = [] as unknown as Record; - v.length = ctor.value.arity; - v.label = ctor.value.label; - for (const [key, tt] of members) { - v[key as number] = walk(tt); - } + v.label = t.value.label; + t.value.fields.forEach(tt => v.push(walk(tt))); return v; } - case 'CArr': { - const v = []; - v.length = ctor.value.arity; - for (const [key, tt] of members) { - v[key as number] = walk(tt); - } - return v; - } - case 'CDict': { + case 'arr': + return t.value.items.map(walk); + case 'dict': { const v = new Dictionary(); - for (const [key, tt] of members) { - v.set(key, walk(tt)); - } + t.value.entries.forEach((tt, key) => v.set(key, walk(tt))); return v; } } - } } } @@ -241,24 +221,16 @@ export function forwarder(ref: Ref): { proxy: Ref, revoker: Ref } { return { proxy, revoker }; } -export function pRec(label: SturdyValue, ... members: Array): Pattern { - return Pattern.PCompound(PCompound({ - ctor: ConstructorSpec.CRec(CRec({ label: label, arity: members.length })), - members: PCompoundMembers(new Dictionary<_embedded, Pattern>( - members.map((p, i) => [i, p] as const).filter(e => e[1]._variant !== 'PDiscard')))})); +export function pRec(label: SturdyValue, ... fields: Array): Pattern { + return Pattern.PCompound(PCompound.rec({ label, fields })); } -export function pArr(... members: Array): Pattern { - return Pattern.PCompound(PCompound({ - ctor: ConstructorSpec.CArr(CArr(members.length)), - members: PCompoundMembers(new Dictionary<_embedded, Pattern>( - members.map((p, i) => [i, p] as const).filter(e => e[1]._variant !== 'PDiscard')))})); +export function pArr(... items: Array): Pattern { + return Pattern.PCompound(PCompound.arr(items)); } export function pDict(... entries: [SturdyValue, Pattern][]): Pattern { - return Pattern.PCompound(PCompound({ - ctor: ConstructorSpec.CDict(CDict()), - members: PCompoundMembers(new Dictionary<_embedded, Pattern>(entries))})); + return Pattern.PCompound(PCompound.dict(new Dictionary<_embedded, Pattern>(entries))); } export function pLit(value: SturdyValue): Pattern { diff --git a/packages/core/src/runtime/skeleton.ts b/packages/core/src/runtime/skeleton.ts index 8b79768..bfb7f4a 100644 --- a/packages/core/src/runtime/skeleton.ts +++ b/packages/core/src/runtime/skeleton.ts @@ -187,11 +187,16 @@ class Node { table[cls] = nextNode; } popCount = 0; - p.value.members.forEach((member, stepIndex) => { + function walkKey(pp: P.Pattern, stepIndex: AnyValue) { path.push(stepIndex); - [popCount, nextNode] = walkNode(nextNode, popCount, stepIndex, member); + [popCount, nextNode] = walkNode(nextNode, popCount, stepIndex, pp); path.pop(); - }); + } + switch (p.value._variant) { + case 'rec': p.value.fields.forEach(walkKey); break; + case 'arr': p.value.items.forEach(walkKey); break; + case 'dict': p.value.entries.forEach(walkKey); break; + } return [popCount + 1, nextNode]; } } diff --git a/packages/timer/src/index.ts b/packages/timer/src/index.ts index dc2fd80..af749aa 100644 --- a/packages/timer/src/index.ts +++ b/packages/timer/src/index.ts @@ -22,7 +22,7 @@ export function boot(ds: Ref) { at ds { during Observe({ "pattern": :pattern PeriodicTick(\Q.lit($intervalMS)) - }) => spawn linked named (preserves`PeriodicTick(${intervalMS})`) { + }) => spawn named (preserves`PeriodicTick(${intervalMS})`) { const thisFacet = Turn.activeFacet; thisFacet.preventInertCheck(); const handle = setInterval(() => thisFacet.turn(() => { @@ -37,7 +37,7 @@ export function boot(ds: Ref) { at ds { during Observe({ "pattern": :pattern TimeLaterThan(\Q.lit($deadlineMS)) - }) => spawn linked named (preserves`TimeLaterThan(${deadlineMS})`) { + }) => spawn named (preserves`TimeLaterThan(${deadlineMS})`) { const thisFacet = Turn.activeFacet; thisFacet.preventInertCheck(); let delta = floatValue(deadlineMS) - (+(new Date())); diff --git a/packages/ws-relay/src/index.ts b/packages/ws-relay/src/index.ts index fbfa9c7..47debfc 100644 --- a/packages/ws-relay/src/index.ts +++ b/packages/ws-relay/src/index.ts @@ -9,12 +9,12 @@ export function boot(ds: Ref, debug: boolean = false) { spawn named 'wsRelay' { at ds { during Observe({ "pattern": :pattern G.Resolved({ - "addr": \Q.lit($addrValue), - "sturdyref": \Q.lit($sturdyRefValue), + "addr": \$addrPatValue, + "sturdyref": \$sturdyRefPatValue, "resolved": \Q.bind(), }) }) => { - const addr = G.toRelayAddress(addrValue); - const sturdyref = Schemas.sturdy.toSturdyRef(sturdyRefValue); + const addr = Q.drop_lit(addrPatValue, G.toRelayAddress); + const sturdyref = Q.drop_lit(sturdyRefPatValue, Schemas.sturdy.toSturdyRef); if (addr && sturdyref) { assert G.fromViaRelay(G.ViaRelay({ "addr": addr,