Skip to content

Instantly share code, notes, and snippets.

@jlongster
Last active January 9, 2021 16:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlongster/6374643 to your computer and use it in GitHub Desktop.
Save jlongster/6374643 to your computer and use it in GitHub Desktop.
very basic CSP in JavaScript
var fs = require('fs');
// machine
function go_(machine, step) {
while(!step.done) {
var arr = step.value();
var state = arr[0];
var value = arr[1];
switch (state) {
case "park":
setImmediate(function() { go_(machine, step); });
return;
case "continue":
if(value instanceof Error) {
step = machine.throw(value);
}
else {
step = machine.next(value);
}
break;
}
}
}
var id = 0;
function go(machine) {
var gen = machine();
gen.id = 'machine' + id++;
go_(gen, gen.next());
}
function put(chan, val) {
return function() {
if(chan.length == 0) {
chan.unshift(val);
return ["continue", null];
} else {
return ["park", null];
}
};
}
function take(chan) {
return function() {
if(chan.length == 0) {
return ["park", null];
} else {
var val = chan.pop();
return ["continue", val];
}
};
}
function chan() {
return [];
}
// signal an error on a channel. This probably needs to look more like
// `put`, instead of eagerly putting it on.
function error(chan, err) {
if(!(err instanceof Error)) {
err = new Error(err);
}
chan.push(err);
}
function timeout(ms) {
var c = chan();
setTimeout(function() {
go(function*() {
yield put(c, true);
});
}, ms);
return c;
}
// forward all values from one channel to another, also does error
// propagation
function forward(chan1, chan2) {
go(function*() {
try {
while(1) {
yield put(chan2, yield take(chan1));
}
}
catch(e) {
error(chan2, e);
}
});
}
// native wrappers
function readFile(path, enc, errorHandler) {
var c = chan();
fs.readFile(path, enc, function(err, res) {
go(function*() {
if(err) { return error(c, err); }
yield put(c, res);
});
});
return c;
};
// testing code
function foo(path) {
var c = chan();
go(function*() {
yield take(timeout(1000));
forward(readFile(path, 'utf-8'), c);
});
return c;
}
go(function*() {
try {
var str = yield take(foo('./main.js'));
console.log(str.slice(0, 20));
}
catch(e) {
// errors are propagated here, even if it occurs in `readFile`
// within `foo`
}
});
@fitzgen
Copy link

fitzgen commented Aug 30, 2013

ported to SpiderMonkey: https://gist.github.com/fitzgen/6393792

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment