Skip to content

Commit

Permalink
feat(eventual-send): breakpoint on delivery by env-options
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed Nov 12, 2023
1 parent e1c63bf commit 2d07ed0
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
58 changes: 56 additions & 2 deletions packages/eventual-send/src/local.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* global globalThis */
import { makeEnvironmentCaptor } from '@endo/env-options';

const { getEnvironmentOption } = makeEnvironmentCaptor(globalThis);

const { details: X, quote: q, Fail } = assert;

const { getOwnPropertyDescriptors, getPrototypeOf, freeze } = Object;
const { getOwnPropertyDescriptors, getPrototypeOf, freeze, hasOwn } = Object;
const { apply, ownKeys } = Reflect;

const ntypeof = specimen => (specimen === null ? 'null' : typeof specimen);
Expand All @@ -13,6 +18,55 @@ const ntypeof = specimen => (specimen === null ? 'null' : typeof specimen);
*/
const isObject = val => Object(val) === val;

const BREAKPOINTS = getEnvironmentOption('BREAKPOINTS', '');

/**
* @type {Record<string, [string, (number | '*')][]>}
*/
// @ts-expect-error doesn't like null __proto__
const BREAKS = { __proto__: null };

const BP_REGEXP = /(.+?)\.(\w+?|\*)=(\d+?|\*)/;

for (const bp of BREAKPOINTS.split(',')) {
if (bp !== '') {
const match = BP_REGEXP.exec(bp);
if (match === null) {
throw Fail`Expected "tagName.methodName=count" ${q(bp)}`;
}
const [_, tag, verb, countStr] = match;
const patts = hasOwn(BREAKS, verb) ? BREAKS[verb] : (BREAKS[verb] = []);
patts.push([tag, countStr === '*' ? countStr : +countStr]);
}
}

const debugApply =
BREAKPOINTS === ''
? (f, obj, _verb, args) => apply(f, obj, args)
: (f, obj, verb, args) => {
const patts = BREAKS[verb] || BREAKS['*'];
if (patts) {
for (const patt of patts) {
const [tag, count] = patt;
if (tag === '*' || tag === obj[Symbol.toStringTag]) {
if (count === '*') {
// eslint-disable-next-line no-debugger
debugger;
break;
} else {
if (count === 0) {
// eslint-disable-next-line no-debugger
debugger;
break;
}
patt[1] = count - 1;
}
}
}
}
return apply(f, obj, args);
};

/**
* Prioritize symbols as earlier than strings.
*
Expand Down Expand Up @@ -96,7 +150,7 @@ export const localApplyMethod = (t, method, args) => {
const ftype = ntypeof(fn);
typeof fn === 'function' ||
Fail`invoked method ${q(method)} is not a function; it is a ${q(ftype)}`;
return apply(fn, t, args);
return debugApply(fn, t, method, args);
};

export const localGet = (t, key) => t[key];
1 change: 1 addition & 0 deletions packages/pass-style/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@fast-check/ava": "^1.1.5"
},
"devDependencies": {
"@endo/eventual-send": "^0.17.6",
"@endo/init": "^0.5.60",
"@endo/ses-ava": "^0.2.44",
"ava": "^5.3.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/pass-style/test/prepare-breakpoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* global process */

process.env.BREAKPOINTS = [
// One line per breakpoint directive.
'Alleged: Bob.foo=*',
'*.bar=0',
].join(',');
28 changes: 28 additions & 0 deletions packages/pass-style/test/test-breakpoints-on-delivery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import './prepare-breakpoints.js';
import { test } from './prepare-test-env-ava.js';

// eslint-disable-next-line import/order
import { E } from '@endo/eventual-send';
import { Far } from '../src/make-far.js';

// Example from test-deep-send.js in @endo/eventual-send

const carol = Far('Carol', {
bar: () => console.log('Wut?'),
});

const bob = Far('Bob', {
foo: carolP => E(carolP).bar(),
});

const alice = Far('Alice', {
test: () => E(bob).foo(carol),
});

// This is not useful as an automated test. Its purpose is to run it under a
// debugger and see where it breakpoints. To play with it, adjust the
// settings in prepare-breakpoints.js and try again.
test('test breakpoints on delivery', async t => {
await alice.test();
t.pass('introduced');
});

0 comments on commit 2d07ed0

Please sign in to comment.