Skip to content

Commit

Permalink
feat(transform-eventual-send): pass HandledPromise endowment to evalu…
Browse files Browse the repository at this point in the history
…ator
  • Loading branch information
michaelfig committed Dec 10, 2019
1 parent 97fc1e7 commit 7a5b74d
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 26 deletions.
7 changes: 5 additions & 2 deletions packages/transform-eventual-send/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agoric/transform-eventual-send",
"version": "1.0.4",
"version": "1.1.0",
"description": "transform-eventual-send",
"main": "dist/transform-eventual-send.cjs.js",
"module": "dist/transform-eventual-send.esm.js",
Expand All @@ -9,15 +9,18 @@
"test": "tape -r esm 'test/**/*.js'",
"lint-fix": "eslint --fix '**/*.{js,jsx}'",
"lint-check": "eslint '**/*.{js,jsx}'",
"build": "rollup -c rollup.config.js"
"build": "node -r esm ./scripts/build-esend.js && rollup -c rollup.config.js"
},
"devDependencies": {
"@agoric/acorn-eventual-send": "^2.0.0",
"@agoric/babel-parser": "^7.6.4",
"@agoric/bundle-source": "^1.0.4",
"@agoric/eventual-send": "^0.5.0",
"@agoric/harden": "^0.0.4",
"@babel/generator": "^7.5.0",
"astring": "^1.4.0",
"esm": "^3.2.5",
"rollup": "^1.16.6",
"rollup-plugin-node-resolve": "^5.2.0",
"ses": "^0.6.3",
"tap-spec": "^5.0.0",
Expand Down
27 changes: 27 additions & 0 deletions packages/transform-eventual-send/scripts/build-esend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#! /usr/bin/env node
import fs from 'fs';
import process from 'process';
import bundleSource from '@agoric/bundle-source';

async function main() {
const esend = require.resolve(`@agoric/eventual-send`);
const bundle = await bundleSource(esend);
const fileContents = `export default ${JSON.stringify(bundle)};`;
try {
await fs.promises.mkdir('src/bundles');
} catch (e) {
if (!e || e.code !== 'EEXIST') {
throw e;
}
}
await fs.promises.writeFile('src/bundles/eventual-send.js', fileContents);
}

main().then(
_ => process.exit(0),
err => {
console.log('error creating src/bundles/eventual-send.js:');
console.log(err);
process.exit(1);
},
);
1 change: 1 addition & 0 deletions packages/transform-eventual-send/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bundles
38 changes: 36 additions & 2 deletions packages/transform-eventual-send/src/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import eventualSendBundle from './bundles/eventual-send';

function makeEventualSendTransformer(parser, generate) {
let HandledPromise;
let evaluateProgram;
const transform = {
closeOverSES(s) {
// FIXME: This should be replaced with ss.evaluateProgram support in SES.
evaluateProgram = src => s.evaluate(src);
},
rewrite(ss) {
// Parse with eventualSend enabled, rewriting to
// HandledPromise.got/set/apply/applyMethod/delete(...)
const source = ss.src;
if (!source.includes(`${'~'}.`)) {
// Short circuit: no instance of tildot.
return ss;
}
const endowments = ss.endowments || {};
if (!('HandledPromise' in endowments)) {
// Use a getter to postpone initialization.
Object.defineProperty(endowments, 'HandledPromise', {
get() {
if (!HandledPromise) {
// Get a HandledPromise endowment for the evaluator.
// It will be hardened in the evaluator's context.
const { source, moduleFormat } = eventualSendBundle;
if (moduleFormat === 'getExport') {
const ns = (evaluateProgram || ss.evaluateProgram)(`(${source})()`);
HandledPromise = ns.HandledPromise;
} else {
throw Error(`Unrecognized moduleFormat ${moduleFormat}`);
}
}
return HandledPromise;
},
});
}

// Parse with eventualSend enabled, rewriting to
// HandledPromise.get/applyFunction/applyMethod(...)
const parseFunc = parser.parse;
const ast = (parseFunc || parser)(source, {
plugins: ['eventualSend'],
Expand All @@ -23,6 +56,7 @@ function makeEventualSendTransformer(parser, generate) {
return {
...ss,
ast,
endowments,
src: actualSource,
};
},
Expand Down
44 changes: 22 additions & 22 deletions packages/transform-eventual-send/test/ses-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import { test } from 'tape-promise/tape';
import SES from 'ses';

import { makeHandledPromise } from '@agoric/eventual-send';

import * as babelParser from '@agoric/babel-parser';
import babelGenerate from '@babel/generator';

Expand All @@ -14,7 +12,10 @@ import * as astring from 'astring';

import makeEventualSendTransformer from '../src';

const shims = [`this.HandledPromise = (${makeHandledPromise})(Promise)`];
// FIXME: This should be unnecessary when SES has support
// for passing `evaluateProgram` through to the rewriter state.
const closeOverSES = (transforms, ses) =>
transforms.forEach(t => t.closeOverSES && t.closeOverSES(ses));

const AcornParser = acorn.Parser.extend(eventualSend(acorn));
const acornParser = {
Expand Down Expand Up @@ -56,7 +57,6 @@ test('eventual send is disabled by default', t => {
test('expression source is parsable', async t => {
try {
const s = SES.makeSESRootRealm({
shims,
transforms: makeEventualSendTransformer(babelParser, babelGenerate),
});
t.equal(
Expand Down Expand Up @@ -90,25 +90,23 @@ test('expression source is parsable', async t => {

test('eventual send can be enabled twice', async t => {
try {
const s = SES.makeSESRootRealm({
shims,
transforms: [
...makeEventualSendTransformer(babelParser, babelGenerate),
...makeEventualSendTransformer(babelParser, babelGenerate),
],
});
const transforms = [
...makeEventualSendTransformer(babelParser, babelGenerate),
...makeEventualSendTransformer(babelParser, babelGenerate),
];
const s = SES.makeSESRootRealm({ transforms });
closeOverSES(transforms, s);
t.equal(
await s.evaluate('"abc"~.[2]'),
'c',
`babel double transform works`,
);
const s2 = SES.makeSESRootRealm({
shims,
transforms: [
...makeEventualSendTransformer(acornParser, acornGenerate),
...makeEventualSendTransformer(acornParser, acornGenerate),
],
});
const transforms2 = [
...makeEventualSendTransformer(acornParser, acornGenerate),
...makeEventualSendTransformer(acornParser, acornGenerate),
];
const s2 = SES.makeSESRootRealm({ transforms: transforms2 });
closeOverSES(transforms2, s2);
t.equal(
await s2.evaluate('"abc"~.[2]'),
'c',
Expand All @@ -127,10 +125,12 @@ test('eventual send can be enabled', async t => {
['babel', babelParser, babelGenerate],
['acorn', acornParser, acornGenerate],
]) {
const s = SES.makeSESRootRealm({
shims,
transforms: makeEventualSendTransformer(parser, generate),
});
const transforms = [
...makeEventualSendTransformer(parser, generate),
];
const s = SES.makeSESRootRealm({ transforms });
closeOverSES(transforms, s);

// console.log(parser('"abc"~.length', { plugins: ['eventualSend'] }));
t.equals(await s.evaluate(`"abc"~.length`), 3, `${name} .get() works`);
t.equals(
Expand Down

0 comments on commit 7a5b74d

Please sign in to comment.