Adapt to syndicate-protocols changes
This commit is contained in:
parent
d737b96465
commit
90a6e2f41a
|
@ -1,7 +1,7 @@
|
|||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
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<AnyValue> | 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<P.Pattern>;
|
||||
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<number, P.Pattern, Ref> {
|
||||
const members = new KeyedDictionary<number, P.Pattern, Ref>();
|
||||
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<AnyValue, AnyValue[], Ref>;
|
||||
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<Ref, AnyValue>();
|
||||
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<AnyValue, P.Pattern, Ref>();
|
||||
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<Ref, P.Pattern>(entries)));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/// SPDX-FileCopyrightText: Copyright © 2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
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<R>(patValue: AnyValue, parser: (v: AnyValue) => R): R | null;
|
||||
export function drop_lit<R>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Assertion, Tuple<Assertion>, 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<Ref, Assertion>(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<Assertion, Tuple<Assertion>, 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<Ref, Assertion>(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<Assertion, Assertion[], Ref>;
|
||||
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<Ref, Assertion>();
|
||||
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>): 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>): Pattern {
|
||||
return Pattern.PCompound(PCompound.rec({ label, fields }));
|
||||
}
|
||||
|
||||
export function pArr(... members: Array<Pattern>): 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>): 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 {
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue